Search code examples
pythontkinterpyinstallerexe

Python tkinter - Compilation is successful but program runs incorrectly when compiled as an Exe


So I created a sort of calculator using tkinter and have made it so that a quick setup creates a save.dat file in the AppData directory and this works as a python script, however when compiled using the line:
pyinstaller --onefile -w file.py it does not work. The exe runs the setup process just fine, but it seems, after some testing, when it reaches the end of the if statement, if save.dat already exists (a dialog box appears and there's a do not show again tick box and an OK button), it does not wait for a response and shuts down. I get a glimpse of it as a background process when I check taskmanager, but no window ever appears. I don't understand what the issue is so I could use some help. Here is a snip of my code:

from tkinter import *
from tkinter import messagebox
import pickle
import os.path
import sys

def saving():
    messagebox.showinfo("Setting Up", "Setup will now begin")
    path = os.path.expanduser("~/AppData/Local")
    os.chdir(path)
    os.makedirs("hydrocalc")
    loc = os.path.expanduser("~/AppData/Local/hydrocalc/save.dat")
    new = "0"
    pickle.dump(new, open(loc, "wb"))
    
popup = Tk()
popup.withdraw()
loc = os.path.expanduser("~/AppData/Local/hydrocalc/save.dat")
if (os.path.exists(loc)):
    i = pickle.load(open(loc, "rb"))
    # then a few variables referring to the calculator
   def world():
       #the functions referring to the calculator
      if (i == "0"):
        popup.deiconify()
        popup["bg"] = "#f0f0f0"
        popup.title("INSTRUCTIONS")
        labelpu = Label(popup, bg="white", text= #instructions on usage, justify="left").grid()
        popup.resizable(width=False, height=False)
        var = StringVar()
        check = Checkbutton(popup, text="Don't Show Again", variable=var, onvalue="1", offvalue="0", 
        bg="#f0f0f0")
        check.deselect()
        check.grid()
        lbl = Label(popup, text=var.get())

        def btnOkay():
            global i
            lbl = Label(popup, text=var.get())
            if (var.get() == "0"):
                popup.withdraw()
                i = "1"
                calc.deiconify()
                world()
            
            elif (var.get() == "1"):
                
                info = open(loc, 'w+')
                new = "1"
                pickle.dump(new, open(loc, "wb"))
                popup.withdraw()
                calc.deiconify()
                i = "1"
                world()
        popup.deiconify()
        btnOK = Button(popup, text="OK", bg="#f0f0f0", justify="center", width=20, 
        command=lambda:btnOkay()).grid()
    elif (i == "1"):
        calc.deiconify()
        world()
else:
    saving()
    messagebox.showinfo("Setup Complete", "Setup is now complete. Please restart the program to 
    continue.")
    sys.exit()


Solution

  • There a couple of changes to be made, refer to the updated code below

    from tkinter import *
    from tkinter import messagebox
    import pickle
    import os.path
    import sys
    
    def saving():
        messagebox.showinfo("Setting Up", "Setup will now begin")
        path = os.path.expanduser(appdata)
        os.chdir(path)
        os.makedirs(appdir)
        loc = os.path.expanduser(pref_file)
        new = "0"
        pickle.dump(new, open(loc, "wb"))
        
    popup = Tk()
    popup.withdraw()
    
    appdata=os.getenv('APPDATA') #modified for my convenience
    appdir=os.path.join(appdata,'MyApp')
    pref_file=os.path.join(appdir,'pref.pickle')
    loc = os.path.expanduser(pref_file)
    
    if (os.path.exists(loc)):
    
        def world():
            #the functions referring to the calculator
            if (i == "0"):
                popup.deiconify()
                popup["bg"] = "#f0f0f0"
                popup.title("INSTRUCTIONS")
                labelpu = Label(popup, bg="white", text='instructions on usage', justify="left").grid()
                popup.resizable(width=False, height=False)
                var = StringVar()
                check = Checkbutton(popup, text="Don't Show Again", variable=var, onvalue="1", offvalue="0", 
                bg="#f0f0f0")
                check.deselect()
                check.grid()
                lbl = Label(popup, text=var.get())
                btnOK = Button(popup, text="OK", bg="#f0f0f0", justify="center", width=20,command=lambda:btnOkay()).grid()
                def btnOkay():
                    global i
                    lbl = Label(popup, text=var.get())
                    if (var.get() == "0"):
                        popup.withdraw()
                        i = "1"
                        #calc.deiconify()
                        print('deiconified calc') #added for debugging
                    
                    elif (var.get() == "1"):
                        
                        info = open(loc, 'w+')
                        new = "1"
                        pickle.dump(new, open(loc, "wb"))
                        popup.withdraw()
                        #calc.deiconify()
                        print('deiconified calc') #added for debugging
                        i = "1"
                        world()
                        popup.deiconify()
    
            elif i == "1":
                #calc.deiconify() commented for debugging
                print('deiconified calc')
                exit() #added for debugging
    
        i = pickle.load(open(loc, "rb"))
        world()
    
    else:
        saving()
        messagebox.showinfo("Setup Complete", "Setup is now complete. Please restart the program to continue.")
        sys.exit()
    
    popup.mainloop()
    

    NOTES

    • You did not have a mainloop() for your program, due to which your window would have never shown up.
    • There was no initial call to the world() function in the if condition.
    • Don't call world() from the elif i == "1": condition, it will lead to infinite recursion.

    I still am not completely clear with as to what exactly do you wanted to achieve, let me know if my code met your requirement. Hope it helped.