Using destroy in tkinter the root disappear but the script keeps running - python

I have done a script that process some images and at the end, it asks you where do you want to save the file. I made it using tkinter (code below). It works fine, the only problem that I have is:
I have an exit button linked with the function destroy and when I click it, the root is closed, but the script is still running, no error appear and I have to stop it manually. If I use quit the script is stopping but the root window freezes and kernel error appear restarting python. I tried to use sys.exit() after the root.mainloop but the script is not going out of the loop. Hope you can help, thank you.
I am using Spider, python 3.7.6, Ipython 7.19.0
root = Tk()
root.geometry('200x150')
# function to call when user press
# the save button, a filedialog will
# open and ask to save file
def save():
filename2 = filedialog.asksaveasfile(mode='wb+',defaultextension=".tif", title="Choose filename")
if not filename2:
return
imwrite(filename2, stack, imagej=True)#
# root.destroy()
button_save = Button(root, text = 'Save', command = lambda : save())
button_save.grid(row=1,column=2)
button_exit=Button(root,text='Exit program', command=root.destroy)
button_exit.grid(row=5,column=2)
root.mainloop()

Ok, I solved it, perhaps it helps someone in the future.
I defined a new function to quit as follows:
def _quit():
root.quit()
root.destroy()
button_exit=Button(root,text='Exit program', command=_quit)

Related

How do you use a tkinter button to make restart the python program?

im new to python. im try to make restart button tkinter for my python gui program. Im still confused how to do it. Can anyone help me ?
You can do this by putting the code that starts the GUI into a function (main) and setting the button command to another function (restart) that destroys the window and calls the main function. Don't forget to call the main function at the bottom of the file. It would look something like this:
import tkinter
def main():
root = tkinter.Tk()
button = tkinter.Button(root, text="Restart", command=lambda: restart(root))
# All the other buttons, labels, etc
tkinter.mainloop()
def restart(window):
window.destroy()
main()
main()

Tkinter hangs after using `destroy` and `quit`

I'm using Tkinter to show a login dialog and then run my main logic.
I intend for the following snippet to close the window (finish the main loop of tk) after clicking the button and just print indefinitely (it is wrapped in while True is in order for the whole script to continue executing, which simulates a real program logic).
But instead, the following snippet hangs the window and fails to close in macOS Ventura with Python 3.10:
from time import sleep
from tkinter import Tk, Button
def quit():
root.quit()
root = Tk()
Button(root, text="Quit", command=quit).pack()
root.mainloop()
while True:
sleep(1)
print("Running a program logic...")
I've tried to run a functional version of this code (which fails the same) and a threaded version of it (which just crashes since an NSWindow must be created on the main thread).
I just really can't wrap my head around it!
EDIT: Fully working example
EDIT 2: Clarify the intention of this code
EDIT 3: Even more minimal code
Try this:
from Tkinter import *
def quit():
global root
root.quit()
root = Tk()
while True:
Button(root, text="Quit", command=quit).pack()
root.mainloop()

How do you close all Tkinter windows when specific window closes?

I have this application in Python Tkinter. There is a Python file which is a main menu. When I click an option in the main menu it imports a python file with code that makes a new window (couldn't use Toplevel for the new window for some reasons). So when I close the main menu it should close all the other windows.
Here is my code for the main menu:
from tkinter import *
root = Tk()
root.geometry("600x600")
def newWindowImport():
import file1
def newWindowImport2():
import file2
newWindow = Button(text="new window", command=newWindowImport).pack()
newWindow2 = Button(text="new window", command=newWindowImport2).pack()
# Here is there a way so that when I exit it destroys the Main Menu as well as the opened windows
exitBtn = Button(text="Exit", command=root.destroy())
root.mainloop()
I tried the root.destroy method but it only destroys the main menu and not all the windows. Is there a way so that when I exit the main menu it destroys the main menu as well as the opened windows? If I were to use Toplevel - how would I use it in a separate file?
I am assuming that your other scripts have individual instances of Tk(), their own mainloop() and are not under a function, if that is the case, you can have all the code in your files under a function and use Toplevel(), example, file1 should look like
def something():
window=Toplevel()
#Rest of the code
And similarly file2, after that in your main program you could do something like this
from tkinter import *
import file1, file2
root = Tk()
root.geometry("600x600")
def newWindowImport():
file1.something()
def newWindowImport2():
file2.something()
newWindow = Button(text="new window", command=newWindowImport)
newWindow.pack()
newWindow2 = Button(text="new window", command=newWindowImport2)
newWindow2.pack()
# Here is there a way so that when I exit it destroys the Main Menu as well as the opened windows
exitBtn = Button(text="Exit", command=root.destroy)
root.mainloop()
You could also let go of the functions and make these changes to have it shorter
newWindow = Button(text="new window", command=file1.something)
newWindow.pack()
newWindow2 = Button(text="new window", command=file2.something)
newWindow2.pack()
The reason for your approach not working would be that each file had it's own mainloop() and hence they couldn't be destroyed when you called root.destroy in the main code.
Also note that I have removed the parentheses () from the command=root.destroy otherwise the it will be called as soon as the program initializes.
EDIT : As also suggested by #martineau in the comments, it's better to use .pack() on the Button instances separately as it provides more flexibility in using the instance later in the program, as opposed to having them hold the value None which is the return from .pack()
Using Toplevel is the correct way to do this, you need to find out why that is not working and correct it. If you did that this question would solve itself. Also, you need to remove the () from the command, it should be like this:
exitBtn = Button(text="Exit", command=root.destroy)

Python tkinter askopenfilename was working for me and is now not responding

I'm developing a program with Python and tkinter that begins with the user adding a text file from their directory. I had built a GUI with tkinter that provided a button to be pressed and a popup window for them to select their file--it was working fine, and then suddenly when I tried to run it it would begin "Not Responding" when I pressed the button meant to launch the popup window.
I am running Python 3.7.3 on Windows 10 in Jupyter notebooks; the tkinter version is 8.6. I have 8 GB of RAM but I'm not using more than 80% of it.
I've tried looking at some similar Stack Overflow questions like the ones here and here:
windows thinks tkinter is not responding
Python tkinter askopenfilename not responding
Trying askopenfilenames() didn't work; neither did adding root.update() or %gui tk.
Here is the code I'm working with:
import tkinter as tk
from tkinter import *
from tkinter import messagebox
from tkinter.filedialog import *
root = Tk()
topFrame=Frame(root)
topFrame.pack()
middleFrame=Frame(root, width=200, height=250,
highlightbackground="yellow",
highlightthickness=3,
borderwidth=2,
relief=RAISED)
middleFrame.pack()
bottomFrame=Frame(root)
bottomFrame.pack()
ourdirectory=[]
def load1():
f1 = askopenfilename(filetypes=(('TXT files','*.txt'), ('All files', '*.*')))
ourdirectory.append(f1)
mylab = Label(topFrame, text="Hello and welcome!")
mylab.pack()
button = Button(bottomFrame, text="Add File", command=load1)
button.grid(row=5, sticky=W)
root.mainloop()
When the "Add File" button is pressed, I expected the program to launch a popup window where the user can navigate in the file directory. Instead, the title text just fades and it doesn't respond--and clicking on the window causes it to announce that it's stopped responding. (This also consistently causes the Jupyter kernel to die.) Still, when I run the code but close the main window without pressing the "File Add" button, it closes fine and nothing freezes or breaks.
I have encountered the same issue when running some code that would open, modify, and overwrite an image. Everything worked as expected until suddenly askopenfilename() started Not Responding and not opening the file dialog window.
I have attempted changing the initial directory of askopenfilename() and calling the method from a separate file and the command line without success.
One of my open windows was a directory (not the same as I was working with) on which file thumbnails failed to load and files could not be opened. Upon closing the window, the screen 'reloaded,' certain programs opened (such as sticky notes, which was previously closed but which typically opens upon restarting), and the method resumed normal functionality.

Restart program tkinter

I am wondering on how I can create a restart button that once clicked, can restart the entire script. What I thought was that you destroy the window then un-destroy it but apparently there is no un-destroy function.
I found a way of doing it for a generic python program on this website: https://www.daniweb.com/programming/software-development/code/260268/restart-your-python-program. I wrote an example with a basic tkinter GUI to test it:
import sys
import os
from tkinter import Tk, Label, Button
def restart_program():
"""Restarts the current program.
Note: this function does not return. Any cleanup action (like
saving data) must be done before calling this function."""
python = sys.executable
os.execl(python, python, * sys.argv)
root = Tk()
Label(root, text="Hello World!").pack()
Button(root, text="Restart", command=restart_program).pack()
root.mainloop()
The following solution works as well but is quite harsh, i.e. the entire environment is lost.
# kills the whole application and starts a fresh one
def restart():
root.destroy()
root = Tk()
root.mainloop()
I would Like to Use this Function:-
First of All Import os Module
import os
Then Use this Code:-
# Restarts the Whole Window
def restart():
root.destroy()
os.startfile("main.py")
Or if You want no console behind then Simply Change the extension of the file to .pyw
And Run this Code:-
# Restarts the Whole Window
def restart():
root.destroy()
os.startfile("main.pyw")

Categories