Convert tkinter to EXE

Question:

Currently, I’m trying to convert my tkinter Python script to an EXE file using cx_freeze. It is somehow not working when I try to add another file. You can see the method I’ve used in the minimum example I’m using below.

import tkinter as tk

import numpy.core._methods, numpy.lib.format 

class Main(tk.Tk):

    def __init__(self, *args, **kwargs):
        tk.Tk.__init__(self, *args, **kwargs)

        self.geometry("700x400")
        self.wm_iconbitmap('test.ico')

        container = tk.Frame(self)

        container.pack(side="top", fill="both", expand = True)

        container.grid_rowconfigure(0, weight=1)
        container.grid_columnconfigure(0, weight=1)

        self.frames = {}

        for F in (StartPage, PageOne):

            frame = F(container, self)
            self.frames[F] = frame
            frame.grid(row=0, column=0, sticky="nsew")

        self.show_frame(StartPage)

    def show_frame(self, cont):
        frame = self.frames[cont]
        frame.tkraise()        
        frame.update_page() # <-- update data on page when you click button

    def get_page(self, page_class):
        return self.frames[page_class]


class StartPage(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller 

        label1 = tk.Label(self, text="What are the sizes?")
        label1.pack()

        L1 = tk.Label(self, text="Length :")
        L1.pack()

        self.E1 = tk.Entry(self)
        self.E1.pack()

        button = tk.Button(self, text="Next", command=lambda: controller.show_frame(PageOne))
        button.pack()

    def update_page(self): # empty method but I need it
        pass   

class PageOne(tk.Frame):

    def __init__(self, parent, controller):
        tk.Frame.__init__(self, parent)
        self.controller = controller

        label1 = tk.Label(self, text="You have insert")
        label1.pack()

        # create empty label at start
        self.label2 = tk.Label(self, text="")
        self.label2.pack()

        button = tk.Button(self, text="Back", command=lambda: controller.show_frame(StartPage))
        button.pack()

    def update_page(self):
        # update label when page is changed
        page1 = self.controller.get_page(StartPage) 
        var = page1.E1.get()
        self.label2['text'] = var


app = Main()
app.mainloop() 

The second script:

import cx_Freeze
import sys
import matplotlib 
import os 
import numpy.core._methods
import numpy.lib.format

base = None 

if sys.platform=='win32':
    base = "Win32GUI"
    

executables = [cx_Freeze.Executable("Show_file.py")]    

cx_Freeze.setup(
        name = "Name",
        options = {
            "build_exe": {
                "packages": ["tkinter","matplotlib"],
                "include_files": ["test.ico"]
            }
        },
        version="0.01",
        executables=executables) 

It works when I do not add an icon when I try to build the EXE file. However, the EXE does not open anymore when I try to add an icon. Furthermore, when I try to add a database Excel file, I get the message that such a file does not exist. All the files are in the correct folder. That is not the problem.

Asked By: Beertje

||

Answers:

The tkinter runtimes and libraries are missing. To include those I would suggest using os.environ()and include the runtimes using the include_files argument as they (briefly) described here.

Using os.environ() is easy. For example it can be done like this:

os.environ["TCL_LIBRARY"] = "<PathToPython>\Python\Python36-32\tcl\tcl8.6"
os.environ["TK_LIBRARY"] = "<PathToPython>\Python\Python36-32\tcl\tk8.6"

Next include the runtimes (DLLs) in the include files arguement:

    options = {"build_exe":{"packages":["tkinter","matplotlib"],"include_files":["test.ico", "<PathToPython>\Python\Python36-32\DLLs\tcl86t.dll", "<PathToPython>\Python\Python36-32\DLLs\tk86t.dll"]}},

Now your whole setup script should look like this:

import sys # Imports are automatically detected (normally) in the script to freeze
import os 

base = None 

os.environ["TCL_LIBRARY"] = "<PathToPython>\Python\Python36-32\tcl\tcl8.6"
os.environ["TK_LIBRARY"] = "<PathToPython>\Python\Python36-32\tcl\tk8.6"

if sys.platform=='win32':
    base = "Win32GUI"


executables = [cx_Freeze.Executable("Show_file.py")]    

cx_Freeze.setup(
        name = "Name",
        options = {"build_exe":{"packages":["tkinter","matplotlib"],"include_files":["test.ico", "<PathToPython>\\Python\Python36-32\DLLs\tcl86t.dll", "<PathToPython>\\Python\Python36-32\DLLs\tk86t.dll"]}},
        version="0.01",
        executables=executables) 

You don’t need all the imports you’re going to use in the setup script, cx_Freeze automatically detects them.

Answered By: Xantium

As the title says Converting tkinter to exe I believe pyinstaller is worth mentioning in this case.

There are some debates on which is better pyinstaller or cx_Freeze on the Internet, but I found pyinstaller simpler and it worked for me out of the box with tkinter. A one-liner in cmd:

pyinstaller.exe --onefile --icon=myicon.ico main.py

--onefile option produces, well, one output file instead of many.

--icon will connect an icon of your choice.

main.py is your main file with the main function.

Answered By: akarilimano