I'm using Python 3.11
and I've made a Markdown reader program.
I've put an icon on a Tkinter window using the iconbitmap
thing and when I run the Python file it all works well.
However, when I ran it as an executable (made using cxfreeze
) and opened a markdown file it returned this error to me:
It looks like it can't invoke the iconbitmap
thing or it can't access icon.ico
.
Here's my code:
import tkinter as tk
import tkinter.filedialog as FileDialog
from tkhtmlview import HTMLLabel
import markdown
import sys
import os
dir_name = os.path.dirname(__file__)
dir_name = dir_name.replace("\\", "\\\\")
icon_dir = dir_name + "\\\\icon.ico"
def display_markdown(markdown_text):
# Convert Markdown to HTML
html_content = markdown.markdown(markdown_text)
# Create the Tkinter window
window = tk.Tk()
window.iconbitmap(icon_dir)
window.title("Markdown Reader")
# Create an HTMLLabel to display the HTML content
html_label = HTMLLabel(window, html=html_content)
html_label.pack(expand=True, fill="both")
# Run the Tkinter main loop
window.mainloop()
def display_markdown_from_file(file_path):
with open(file_path, 'r', encoding='utf-8') as file:
markdown_text = file.read()
display_markdown(markdown_text)
if __name__ == "__main__":
if len(sys.argv) == 2:
display_markdown_from_file(sys.argv[1])
else:
file = FileDialog.askopenfile(mode="r", filetypes=[("Markdown Files", "*.md *.markdown")], title="Open Markdown File")
if file is not None:
content = file.read()
display_markdown(content)
The problem becomes clearer if we print the paths.
...
import sys
import os
dir_name = os.path.dirname(__file__)
dir_name = dir_name.replace("\\", "\\\\")
icon_dir = dir_name + "\\\\icon.ico"
print(__file__)
print("dir_name", dir_name)
print("icon_dir", icon_dir)
...
Note: The icon file (icon.ico) exists in the same directory as the Python script. I've simplified your program so that it only takes arguments and shows a GUI.
Python file:
(env) F:\cxexe>test.py qwerty
F:\cxexe\test.py
dir_name F:\\cxexe
icon_dir F:\\cxexe\\icon.ico
Output for exe:
(env) F:\cxexe>cxfreeze -c test.py --target-dir dist --include-files icon.ico
(env) F:\cxexe>cd dist
(env) F:\cxexe\dist>test.exe qwerty
test.py
dir_name
icon_dir \\icon.ico
Traceback (most recent call last):
...
return self.tk.call('wm', 'iconbitmap', self._w, bitmap)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
_tkinter.TclError: bitmap "\\icon.ico" not defined
As we can see, the dir_name is now an empty string.
Backslashes become redundant in the file name.
>>> import os
>>> path = "test.py" # __file__
>>> os.path.split(path)
('', 'test.py')
>>> os.path.dirname(path)
''
>>> print(os.path.dirname(path) + "\\\\icon.ico")
\\icon.ico
Docs recommendation
...
import sys
import os
icon_file = "icon.ico"
def find_data_file(filename):
if getattr(sys, "frozen", False):
# The application is frozen
datadir = os.path.dirname(sys.executable)
else:
# The application is not frozen
# Change this bit to match where you store your data files:
datadir = os.path.dirname(__file__)
return os.path.join(datadir, filename)
def display_markdown(markdown_text):
...
window.iconbitmap(find_data_file(icon_file))
...