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()
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)
Related
I have the next files inside a folder:
When I execute idsave.py from within PyCharm or from the file location inside the command line it opens this file selection window when it's supposed to do it:
But if I run the desktop shortcut I made, it does not ask me to choose a file, when running gtk-launch idsave.desktop and click the button that triggers said window I get the next error:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib64/python3.9/tkinter/__init__.py", line 1892, in __call__
return self.func(*args)
File "/home/username/Programacion/Python/idsave/idsave.py", line 39, in open_file
dir_path = open('dir.txt', 'r')
FileNotFoundError: [Errno 2] No such file or directory: 'dir.txt'
Even though when checking if the file exists with os.listdir() it shows that the file in fact exists:
print(os.listdir(dir))
[file, file, file, 'dir.txt', 'idsave.py', file, file]
My .desktop shortcut looks like this:
[Desktop Entry]
Name=IdSave
GenericName=Idea Saver
Comment=Save Your Ideas
Exec=/home/username/Programacion/Python/idsave/idsave.py
Icon=/home/username/Programacion/Python/idsave/icon.jpg
Type=Application
Categories=Development;
The function that triggers that window is this:
def open_file():
dir_path = open('dir.txt', 'r')
root.filename = filedialog.askopenfilename(
initialdir=dir_path.readline(),
filetypes=(("All Files", "*.*"))
)
dir_path.close()
I already tried with './dir.txt' '../dir.txt' and the absolute path of the file, but the desktop entry still gives me the same error.
What am I doing wrong?
Instead of creating a desktop shortcut, you can create a bash script (.sh file) with the following code in a text editor and place it on your desktop. Name it idsave.sh.
cd "/home/username/Programacion/Python/idsave/"
python3 idsave.py
If on double-clicking the script doesn't run and opens your text editor instead, you can right click on idsave.sh and click on Properties. Then click on the Permissions tab and check Allow executing file as program (or something similar). Then click on OK.
Now you will be able to double click on idsave.sh and your Python program will launch as expected.
This will probably solve your problem.
i know i should share the code instead of image but please refer image for my path.
This is my path of project
setup file contains
from Functions.MainWindow import Ui
def OpenMainwindow(self):
try:
app = QtWidgets.QApplication(sys.argv)
window = Ui()
window.show()
app.exec_()
# Ui()
except Exception as es:
print(es)
And the Inside form file i loaded UI file from other folder
uic.loadUi(r"./BAJARANGBALI/Forms/MainWindow.ui", self)
but when i make exe using auto-py-to-exe during running of exe file it shows file not found.[Errno 2] No such file or directory: './Forms/MainWindow.ui'.
I tried every path ,Even tried by moving exe to that path but no result.
I am new to stackoverflow i hope i tried my best to describe my issue.Thanks
I made a GUI for a python program that allows me to read a csv file and display the data on the GUI. The GUI works perfectly fine when I run the program through IDLE. However when I try to run the program file as it is from Windows Explorer it shows the following error.
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Program Files\WindowsApps\PythonSoftwareFoundation.Python.3.9_3.9.1776.0_x64__qbz5n2kfra8p0\lib\tkinter\__init__.py", line 1892, in __call__
return self.func(*args)
File "C:\Python\gui1.py", line 43, in find_result
with open("RESULTS.csv") as a:
FileNotFoundError: [Errno 2] No such file or directory: 'RESULTS.csv'
This is the program code:
import tkinter as tk
import csv
root=tk.Tk()
root.title('Results')
tk.Label(root,text="Enter your Roll Number:").grid(row=1,column=1,sticky=tk.W)
tk.Label(root,text="Name:").grid(row=4,column=1,sticky=tk.W)
tk.Label(root,text="Total (Core 5 Subjects):").grid(row=5,column=1,sticky=tk.W)
tk.Label(root,text="Total (Best 5 Subjects):").grid(row=6,column=1,sticky=tk.W)
tk.Label(root,text="Percentage:").grid(row=7,column=1,sticky=tk.W)
tk.Label(root,text="Rank:").grid(row=8
,column=1,sticky=tk.W)
rno=tk.StringVar()
name_=tk.StringVar()
t1_=tk.StringVar()
t2_=tk.StringVar()
perc_=tk.StringVar()
rank_=tk.StringVar()
tk.Entry(root, textvariable=rno,justify=tk.RIGHT).grid(row=1,column=2,padx=3,pady=3)
def find_result():
tk.Label(root,textvariable=name_,justify=tk.RIGHT).grid(row=4,column=2,sticky=tk.E)
tk.Label(root,textvariable=t1_,justify=tk.RIGHT).grid(row=5,column=2,sticky=tk.E)
tk.Label(root,textvariable=t2_,justify=tk.RIGHT).grid(row=6,column=2,sticky=tk.E)
tk.Label(root,textvariable=perc_,justify=tk.RIGHT).grid(row=7,column=2,sticky=tk.E)
tk.Label(root,textvariable=rank_,justify=tk.RIGHT).grid(row=8,column=2,sticky=tk.E)
with open("RESULTS.csv") as a:
reader=csv.reader(a)
for i in reader:
if i!=[]:
if i[0]==rno.get():
name=i[1][2:]
t1=i[19]
t2=i[20]
perc=i[21]
rank=i[22]
name_.set(name)
t1_.set(t1)
t2_.set(t2)
perc_.set(perc)
rank_.set(rank)
tk.Button(root, text="Check your Result",command=find_result).grid(row=2,column=2)
root.mainloop()
Opening program with IDLE:
Opening program through Explorer:
open("RESULTS.csv") looks for that file in the current working directory, whatever that happens to be. This must be different for the two different ways you run the code. Do one of the following.
Give open an absolute path to the file instead of a relative one. If you know the location of the data file relative to the location of the program file, use __file__, which has the location of the program file, as the starting point. Note 1: that when working interactively, without running a file, __file__ does not exist. Note 2: If you do not understand 'absolute path', do a web search.
Explicitly set the current directory to the one containing the file with os.chdir(path). where path is absolute, not relative. This is more useful if opening several files in that directory.
I have strange behavior of the below code.
When I run this code from PyCharm level it works properly and return this window (including gif with Python logo!):
Window with Python logo
When I run the same python code but with using .bat and .vbs files. It will give me such error:
Error
One more thing... ".vbs" file is automatically started when windows (operating system) is turn on. ".vbs" file opening ".bat" file and ".bat" file opening ".py" file.
Do you know why python code is no able to find ".gif" when it is starting with windows operating system.
Here is code:
import tkinter as tk
class KeypadTest():
def __init__(self, master):
self.master = master
self.time_display = tk.IntVar()
global logo
logo = tk.PhotoImage(file="indeks_gif.gif")
tk.Label(self.master, height=10, width=10 , textvariable=self.time_display,bg="red").pack(side="right")
Info = """INFO"""
tk.Label(self.master,compound = tk.CENTER,image=logo,text=Info).pack()
master = tk.Tk()
KT = KeypadTest(master)
master.mainloop()
The program can't find the file. I suspect this is because you are not running the Python program from the directory where the gif file is located.
This can be adressed by supplying the full path to the image or by running the bat file from that directory regardless of where the bat file is located. I haven't tried with vbs file but I think the problem is the same.
You can experiment by including in your program a line which prints out the working directory when it starts.
import os
print(os.getcwd())
I've successfully created an EXE file from python tkinter GUI which includes images. see the following code:
lblLogo=Label(main)
lblLogo.grid(row=3,column=11,rowspan=4)
try:
filelocation="C:/Documents/Python/ScreenPartNumberProgram/"
KasonLogo=PhotoImage(file=filelocation+"KasonLogo.png")
KasonLogo=KasonLogo.zoom(25,20)
KasonLogo=KasonLogo.subsample(50,50)
lblLogo.config(image=KasonLogo)
icon=PhotoImage(file=filelocation+"KasonLogo.png")
main.tk.call('wm','iconphoto',main._w,icon)
except:
print("warning: could not load photos")
lblLogo.config(text="[KasonLogo.png]")
the exe file opens and works perfectly on my computer. I used this command to get the .exe:
pyinstaller --onefile --noconsole myscript.py
The only problem is this file requires the image to be in the same folder or it doesn't show on the label. How can I get the image bundled into the EXE without requiring an external file?
Thanks in advance
edit:
I looked at the links provided,did more research, and still haven't solved the issue. The program works only if the image is in the same folder. I'd really like to make it work without requiring an external image file. the resource_path technique doesn't seem to work for me either...
I also tried modifying my code to use PIL's ImageTk and same issue. program loads image only if the external image file is in the folder with it.
HOLY COW ! After a few more days of headaches I FINALLY found an approach that works... here is what I did to get the program to work without requiring an external image file:
step 1: encode the image file (note that it must be a GIF. you can convert it using paint):
import base64
with open("MyPicture.gif", "rb") as image_file:
encoded_string = base64.b64encode(image_file.read())
print(encoded_string)#print string to copy it (see step 2)
step 2: the next step is to copy and paste the string into a separate myimages.py file and
store it as variable. for example:
imageString = b'R0lGODlhyADIAPcAAAA .....blah blah really long string.......'
step 3: then import the myimages.py into main program and call the variable
from myimages import *
pic=imageString#GIF decoded to string. imageString from myimages.py
render = PhotoImage(data=pic)
myLabel.config(image=render)
step 4: in the spec file: include the myimages.py as data
# -*- mode: python -*-
block_cipher = None
#instructions: pyinstaller --onefile --noconsole myProgram.spec
file_name = 'myProgram'
add_files=[('myimages.py','module')]
a = Analysis([file_name+'.py'],
pathex=['C:\\Program Files (x86)\\Python36-32\\Scripts'],
binaries=[],
datas=add_files,
hiddenimports=[],
hookspath=[],
runtime_hooks=[],
excludes=exclude_list,
win_no_prefer_redirects=False,
win_private_assemblies=False,
cipher=block_cipher)
pyz = PYZ(a.pure, a.zipped_data,
cipher=block_cipher)
exe = EXE(pyz,
a.scripts,
a.binaries,
a.zipfiles,
a.datas,
name=file_name,
debug=False,
strip=False,
upx=True,
runtime_tmpdir=None,
console=False )
step 5: finally you can compile to EXE:
pyinstaller --onefile --noconsole myProgram.spec
SIGH If anyone has a better solution, please post it here. until then I'm glad something works...
I ran into the same issue when I was wanting to include a .ico file to use as the icon for my tkinter app. Here's how I got it to work:
When building the .exe file with PyInstaller, I specified the --add-data option with the full path to my .ico.
When the app starts up, it has to unpack everything from the .exe in a temp directory, so I get the path to that temp directory and use it to specify the temp location of my .ico file.
Before the mainloop is kicked off, and using 'tempfile' to get the temp file directory and 'glob' to check for a file pattern match:
tempdir = tempfile.gettempdir()
icon_path = tempdir + '\\' + 'next_subdirectory_pattern' + '\\' + '*.ico'
icon_matches = glob.glob(icon_path)
if len(icon_matches) > 0:
logo = icon_matches[0]
else:
logo = ''
tk.Tk.iconbitmap(self, default=logo)
Probably not the most eloquent way to do it, but it works.
Here's how I did it...
To bundle the image with the executable:
Use the following command to save your icon to a folder called "icon" that will be generated in the "C:\Users<username>\AppData\Local\Temp_MEI123456" folder generated by pyinstaller at runtime:
--add-data=C:\absolute\path\to\your\ICON.ico;icon
My full command line, the string I type into the python terminal (i'm using pycharm IDE) to generate my EXE, looks like this:
pyinstaller -w -F -i=C:\absolute\path\to\your\ICON.ico --add-data=C:\absolute\path\to\your\ICON.ico;icon -n=MyEXEsNameV1 main.py
(For debug it is helpful to omit -w and add --debug=all)
doc reference: https://pyinstaller.readthedocs.io/en/stable/usage.html#options-group-what-to-bundle-where-to-search
To access the image in my python script main.py:
I used the following code to setup the tk window:
import tkinter as tk
from os import path
# main widget
self.root = tk.Tk(master)
self.root.title('Window Title Bar Name V1.0')
self.root.minsize(1234, 1234)
# get icon
try:
# Get the absolute path of the temp directory
path_to_icon = path.abspath(path.join(path.dirname(__file__), 'icon/GAUGE-ICON.ico'))
# set the icon of the tk window
self.root.iconbitmap(path_to_icon)
except:
pass
doc reference: https://pyinstaller.readthedocs.io/en/stable/runtime-information.html
In addition to accepted answer I want to add modified version:
from PIL import Image, ImageTk
from res import *
#res is a module with your base64 image string and in my case variable is icon_base64
from base64 import b64decode
pic_as_bytes=ImageTk.BytesIO(icon_base64)
my_image=Image.open(pic_as_bytes)
Please note this code will work in Python3, but could not in Python2 cause it needs differrent aproach and more conversions (the link below has exactly an example for Python2).
For more info please refer to https://github.com/Ariel-MN/Tkinter_base64_Images/blob/master/tkinter_base64_image-ico.py
I tried the following methods. The 2nd option worked for me.
Use the command you mentioned to generate exe and copy the exe file into the source folder of your project (Where the python file is).
I fix it using auto-py-to-exe which uses pyinstaller. There you
can see the command generated.
pyinstaller --noconfirm --onedir --windowed --add-data "path/assets/" "path/gui.py"
First, try using --onefile instead of --onedir. Mine didn't work
when I used --onefile. So I had to covert --onedir.