I've created an app with tkinter to practise which resembles a virtual purse to keep track of your expenditures. You can add deposits and withdrawals of money in different categories, which is all then shown in a treeview using the tkinter ttk TreeView widget. Here is an image so it is easier to understand:
When I run it with my main.py file like any other python file it works perfectly, but when I build it into an executable file using cx_freeze, even when the build works and the app runs, the site of the TreeView widget, which is reached through de "Historial" menu, doesn't load and it shows completely empty, but it doesn't crash or raise any error:
Here is my setup.py file code:
import sys
import os
from cx_Freeze import setup, Executable
application_title = "Monedero App"
main_python_file = "main.py"
PYTHON_INSTALL_DIR = os.path.dirname(sys.executable)
os.environ['TCL_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tcl8.6')
os.environ['TK_LIBRARY'] = os.path.join(PYTHON_INSTALL_DIR, 'tcl', 'tk8.6')
base = None
if sys.platform == "win64":
base = "Win64GUI"
elif sys.platform == "win32":
base = "Win32GUI"
options = {
"build_exe": {
"packages": ["tkinter", "tkinter.ttk", "shelve", "datetime"],
"include_files": [
"D:\\Programacion\\Projects and exercices\\Monedero\\imagenes\\logo.ico",
(os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tk86t.dll'), os.path.join('lib', 'tk86t.dll')),
(os.path.join(PYTHON_INSTALL_DIR, 'DLLs', 'tcl86t.dll'), os.path.join('lib', 'tcl86t.dll')),
],
}
}
setup(
name = application_title,
version = "0.1",
description = "Test 1",
options = options,
executables = [Executable(main_python_file, base=base)],
)
Another important part is that I use the shelve python library to save my data. I do it this way because first I used sqlite to do it but I got the same problem and I thought that sqlite might be the issue. Now I don't know what the issue might be.
I'll also attach the TreeView widget configuration function code, in the case I should change something from there:
def configure(self):
self.parent.refresh()
try:
self.historial_frame.destroy()
except:
pass
self.title.config(
fg = "white",
bg = "black",
font = ("Arial", 30),
padx = 110,
pady = 20
)
self.title.pack(side = tk.TOP, fill = tk.X, expand = tk.YES)
self.historial_frame = tk.Frame(self)
style = ttk.Style()
style.configure("mystyle.Treeview", highlightthickness = 0, bd = 0, font = ('Calibri', 11)) # Modify the font of the body
style.configure("mystyle.Treeview.Heading", font = ('Calibri', 13,'bold')) # Modify the font of the headings
style.layout("mystyle.Treeview", [('mystyle.Treeview.treearea', {'sticky': 'nswe'})]) # Remove the borders
self.historial = ttk.Treeview(self.historial_frame, columns = ('Fecha', 'Cantidad', 'Descripción'), style = "mystyle.Treeview", height = 10)
self.historial.column("#0", width = 150, stretch = tk.NO)
self.historial.column("#1", width = 150, stretch = tk.NO)
self.historial.column("#2", width = 100, stretch = tk.NO)
self.historial.column("#3", width = 200, minwidth = 100, stretch = tk.YES)
self.historial.heading("#0", text = "Categoría", anchor = tk.W)
self.historial.heading("#1", text = "Fecha", anchor = tk.W)
self.historial.heading("#2", text = "Cantidad", anchor = tk.W)
self.historial.heading("#3", text = "Descripción", anchor = tk.W)
self.historial.grid(row=0, column=0, columnspan=15, padx=10, pady=10, sticky="nsew")
scrollbar = ttk.Scrollbar(self.historial_frame, orient = tk.VERTICAL, command = self.historial.yview)
scrollbar.grid(row=0, column=15, sticky="nse", pady="10")
self.historial.configure(yscrollcommand = scrollbar.set)
self.parent.import_categories()
total = self.fill_historial()
totalLabel = tk.Label(self.historial_frame, text = "Balance total: ")
totalLabel.config(font = ('Calibri', 13))
totalLabel.grid(row = 1, column = 0, sticky = "w", pady = 10, padx = 5)
total_dato = tk.StringVar()
total_dato.set("{:.2f}".format(total) + " €")
totalLabel_dato = tk.Label(self.historial_frame, textvariable = total_dato, justify = 'left')
totalLabel_dato.config(font = ('Calibri', 13))
totalLabel_dato.grid(row = 1, column = 1, sticky = "w", pady = 10, padx = 5)
self.historial.tag_configure('odd', font = 'Calibri 13')
deleteLabel = tk.Label(self.historial_frame, text = "Eliminar registro: ")
deleteLabel.grid(row = 1, column = 3, sticky = "w", pady = 10, padx = 5)
deleteButton = tk.Button(self.historial_frame, text="Borrar", command=self.delete_register)
deleteButton.grid(row = 1, column = 4, sticky = "w", pady = 10, padx = 5)
self.historial_frame.pack()
self.pack(fill = "both")
So, if anyone has an idea of what's happening please it will be very much appreciated. If more info is needed please ask. The spanish names and words on the code or images are because I'm from Spain :).
Thank you!
Here is an alternative, by using pyinstaller
.
In your terminal say:
pip install pyinstaller
and after that just use this command in the terminal, like
pyinstaller -F -w -i"path.ico" name.py
Here,
-w
means the program should be windowed, since it uses GUI-F
means the program should be made into one file and not a directory-i"path.ico"
this can be used to set an icon for your exeand make sure to use the exe in the dist
folder and if you use any image files then copy the exe to the project directory.
Take a look at the documentation
Hope it cleared your doubt, if any errors do let me know
Cheers