I'm trying to do something when a window is manually closed in tkinter and don't know a method/function to do so. A simple example of what im trying to do in a smaller scale.
from tkinter import *
root = Tk()
rootIsClosed = False # how to do this? How to make it True?
if rootIsClosed: # ?
new_win = Tk()
x = Label(new_win, text='why did you close the program').pack()
You can look at this answer which talks about how to handle exiting a window.
In short, you can do this:
from tkinter import *
root = Tk() #create new root
def on_close():
#this is the code you provided
new_win = Tk()
x = Label(new_win, text='why did you close the program').pack()
root.protocol("WM_DELETE_WINDOW", on_close) # main part of the code, calls on_close
root.mainloop()
Note that this doesn't allow you to actually close the window, so you can do this to close the window:
from tkinter import *
root = Tk()
def on_close():
new_win = Tk()
x = Label(new_win, text='why did you close the program').pack()
root.destroy() #only difference, root.destroy closes the original window.
root.protocol("WM_DELETE_WINDOW", on_close)
root.mainloop()
Related
I am trying to build a simple hangman game. I want to have a window at the beginning to ask for the "secret word". I then want that window to close and have another window open with the game. I can't think of a way to do this without building the entire game within a funciton. How is best to accomplish this?
I believe what you are looking for is a Toplevel window and it behaves just like a normal root window. Below is a quick and dirty example:
import tkinter as tk
root = tk.Tk()
root.title("Game window")
root.iconify()#Hide from user site, still exists as a minimised window
def submitSecretWord():
#code to collect secret word or what ever
root.deiconify()#Make visible
second_window.destroy()#close second window
#make toplevel window
second_window = tk.Toplevel(master=root)
#make widgets
secret_word_entry = tk.Entry(master=second_window)#Belongs to the second window
submit_button = tk.Button(master=second_window, text="Submit secret word", command=submitSecretWord) #Belongs to the second window
#pack widgets
secret_word_entry.pack(side=tk.LEFT)
submit_button.pack(side=tk.RIGHT)
root.mainloop()
Create another window? Try this:
use multiple functions
from tkinter import *
from turtle import onclick
def gameWindow(word):
window = Tk()
Label(text=word).pack()
# your game code
def anotherGuess():
window.destroy()
getWord()
Button(text='another guess?', command=anotherGuess).pack()
window.mainloop()
def getWord():
window = Tk()
entry = Entry(master=window)
entry.pack()
def onclick():
word = entry.get()
window.destroy()
gameWindow(word)
btn = Button(master=window, text="submit", command=onclick)
btn.pack()
window.mainloop()
def main():
getWord()
if __name__ == '__main__':
main()
I'm trying to update my cursor while my program is busy.
This snippet works:
import tkinter as tk
def button():
root.configure(cursor="watch")
root = tk.Tk()
root.geometry("300x500")
button_1 = tk.Button(master=root,command=button,width=10)
button_1.grid()
root.mainloop()
When I click the button the cursor changes
But this snippet fails:
import tkinter as tk
def button():
root.configure(cursor="watch")
input("Force a pause")
root = tk.Tk()
root.geometry("300x500")
button_1 = tk.Button(master=root,command=button,width=10)
button_1.grid()
root.mainloop()
It only updates the cursor if I make another window active (or after entering some dummy input)
I've tried adding
root.configure(cursor="watch")
root.update()
but it still doesn't work (and anyway the tk man says it's a bad idea to put an update() in a callback)
Any suggestions would be welcome.
Thanks for your time.
Your code update the cursor but it's only done after your busy process is terminated.
So you can execute your busy process in a thread to prevent the user interface to freeze.
import tkinter as tk
import threading
def worker():
for x in range(0, 100000):
print(x)
root.config(cursor="arrow")
def button():
root.config(cursor="watch")
threading.Thread(target=worker).start()
root = tk.Tk()
root.geometry("300x500")
root.config(cursor="arrow")
button_1 = tk.Button(master=root, command=button, width=10)
button_1.grid()
root.mainloop()
I have primary.py:
from tkinter import *
from tkinter.filedialog import askopenfilename
from tkinter import ttk
import multiprocessing as mp
import other_script
class GUI:
def __init__(self, master):
self.master = master
def file_select():
path = askopenfilename()
if __name__ == '__main__':
queue = mp.Queue()
queue.put(path)
import_ds_proc = mp.Process(target=other_script.dummy, args=(queue,))
import_ds_proc.daemon = True
import_ds_proc.start()
# GUI
root = Tk()
my_gui = GUI(root)
# Display
frame = Frame(width=206, height=236)
frame.pack()
ttk.Button(frame, text="Select", command=file_select).pack(anchor='nw')
# Listener
root.mainloop()
And other_script.py:
def dummy(parameter):
pass
When running this, upon selection of a file, a second GUI window appears. Why? This is undesired behavior, I instead want dummy to run.
Thanks.
Just like with multiprocessing, you need to place the code to do with tkinter and making your window within the entry point to your program (such that it is not ran more than once through another process).
This means moving the if __name__ == "__main__" clause to the 'bottom' of your program and placing the code to do with tkinter in there instead. The entry point to your multiprocessing will still be protected as it is called after an event, which is defined within the start point.
Edit:
The entry point is where your program is entered from, normally when you say if __name__ == "__main__".
By moving the tkinter code into the entry point, I mean something like this:
if __name__ == "__main__":
root = Tk()
my_gui = GUI(root)
frame = Frame(width=206, height=236)
frame.pack()
ttk.Button(frame, text="Select", command=file_select).pack(anchor='nw')
root.mainloop()
(At the 'bottom' of your program, i.e. after all functions are defined.)
I am using python 3.
If I opan an error messagebox, i get two frames, one is emty and one is the error-window. That is my code:
from tkinter import messagebox
messagebox.showwarning('warning', 'warning')
Everything works correctly in your example. The empty window is the main window of Tk. It is always open when you start any Tk program. You can minimize it if you want, but closing it terminates the main loop.
Try this:
root = tkinter.Tk()
root.withdraw()
messagebox.showwarning('warning', 'warning')
Thank you DYZ,
in my code is no main window, (eg.: main = Tk() ... main.mainloop), because of that the warning massage create one. I could solve the problem by create one and minimize it. at the end of massagebox I destroyed it to continue in code.
from tkinter import *
from tkinter import messagebox
main = Tk()
main.geometry("500x400+300+300")
def message():
main.geometry("0x0")
messagebox.showwarning("Say Hello", "Hello World")
main.destroy()
B1 = Button(main, text = "Start Dialog",fg="dark green", command = message)
B1.pack()
main.mainloop()
print("finish dialog")
I was testing the Toplevel() feature of python Tkinter and I was wondering if a user closes one window how do I keep the other one from closing as well?
from Tkinter import *
root = Tk()
top = Toplevel()
root.mainloop()
Calling transient, closing toplevel will not close the all windows.
from Tkinter import *
root = Tk()
top = Toplevel()
top.title('TopLevel window')
top.transient(root) # <------
root.mainloop()