Closing Tkinter window and opening another - python

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()

Related

Opening a new window using a link in tkinter

How do I open a new window using a link in tkinter .
(For eg : in a login window i want to add a link that says "New user ? click here" and when I click on "click here" it takes me to the register window .
Please help me
enter image description here
[1]: https://i.stack.imgur.com/K5GV0.png
Please click the above link to see the image
Creating new toplevel windows works almost exactly the same as creating new widgets.
Toplevel windows are created using the Toplevel function:
t = Toplevel(parent)
Unlike regular widgets, you don't have to "Grid" a toplevel fo it to appear on screen. Once you've created a toplevel you can add children widgets within and grid them like in the main window. In other words toplevel behaves exactly like the automatic created root window.
To destroy a window use the method:
window.destroy()
You can open new windows in tkinter with the tkinter.Toplevel() command.
import tkinter as tk
class Gui:
"""Gui class"""
def __init__(self):
self.root = tk.Tk()
self.new_window = tk.Button(master=self.root, text="Open new window", width=20, pady=4, command=self.new_window)
self.new_window.pack()
self.root.mainloop()
def new_window(self):
"""Create a new top level window"""
new_window = tk.Toplevel()
tk.Label(master=new_window, text="This is a new window").pack()
if __name__ == '__main__':
Gui()
You can create a function to open a new window and then bind it to that Label, for example:
import tkinter as tk
def newWindow():
# Window object (top level)
newWindow = Toplevel(master)
# Title
newWindow.title("New Window 1")
# Geometry
newWindow.geometry("300x300")
root = tk.Tk()
label = tk.Label(text="Hello!", width=50, height=10, master=root)
label.pack()
label.bind("<Button-1>", newWindow)

How do I destroy a tkinter frame?

I am trying to make a tkinter frame that will contain an entry field and a submit button. When the submit button is pressed, I want to pass the entry string to the program and destroy the frame. After many experiments, I came up with this script:
from tkinter import *
from tkinter import ttk
import time
root = Tk()
entryframe = ttk.Frame(root)
entryframe.pack()
par = StringVar('')
entrypar = ttk.Entry(entryframe, textvariable=par)
entrypar.pack()
submit = ttk.Button(entryframe, text='Submit', command=entryframe.quit)
submit.pack()
entryframe.mainloop()
entryframe.destroy()
parval = par.get()
print(parval)
time.sleep(3)
root.mainloop()
When the "Submit" button is pressed, the parameter value is passed correctly to the script and printed. However, the entry frame is destroyed only after 3 seconds (set by the time.sleep function).
I want to destroy the entry frame immediately.
I have a slightly different version of the script in which the entry frame does get destroyed immediately (although the button itself is not destroyed), but the value of par is not printed:
from tkinter import *
from tkinter import ttk
import time
root = Tk()
entryframe = ttk.Frame(root)
entryframe.pack()
par = StringVar('')
entrypar = ttk.Entry(entryframe, textvariable=par)
entrypar.pack()
submit = ttk.Button(root, text='Submit', command=entryframe.destroy)
submit.pack()
entryframe.mainloop()
# entryframe.destroy()
parval = par.get()
print(parval)
time.sleep(3)
root.mainloop()
How can I get both actions, namely the entry frame destroyed immediately and the value of par printed?
Note 100% sure what you are trying to do but look at this code:
from tkinter import *
from tkinter import ttk
def print_results():
global user_input # If you want to access the user's input from outside the function
# Handle the user's input
user_input = entrypar.get()
print(user_input)
# Destroy whatever you want here:
entrypar.destroy()
submit.destroy()
# If you want you can also destroy the window: root.destroy()
# I will create a new `Label` with the user's input:
label = Label(root, text=user_input)
label.pack()
# Create a tkitner window
root = Tk()
# Create the entry
entrypar = ttk.Entry(root)
entrypar.pack()
# Create the button and tell tkinter to call `print_results` whenever
# the button is pressed
submit = ttk.Button(root, text="Submit", command=print_results)
submit.pack()
# Run tkinter's main loop
# It will stop only when all tkinter windows are closed
root.mainloop()
# Because of the `global user_input` now we can use:
print("Again, user_input =", user_input)
I defined a function which will destroy the entry and the button. It also creates a new label that displays the user's input.
I was able to accomplish what I wanted using the wait_window method. Here is the correct script:
from tkinter import *
from tkinter import ttk
root = Tk()
entryframe = ttk.Frame(root)
entryframe.pack()
entrypar = ttk.Entry(entryframe)
entrypar.pack()
submit = ttk.Button(entryframe, text='Submit', command=entryframe.destroy)
submit.pack()
entrypar.wait_window()
parval = entrypar.get()
print(parval)
close_button = ttk.Button(root, text='Close', command=root.destroy)
close_button.pack()
root.mainloop()
My intention was not fully apparent in my original question, and I apologize for that. Anyway, the answers did put me on the right track, and I am immensely thankful.

Tkinter: Bind <Enter> event to entire window (but not all widgets)

My goal is to bind an Event to the window. For example I want a function called when the mouse pointer enters the window. The code below does this but sadly the function is also called whenever the mouse pointer enters the Button. I tried B.unbind("<Enter>") but it does not work. Any help would be appreciated
import tkinter as tk
root = tk.Tk()
def function(event):
print("Hello World")
B = tk.Button(root, text ="Label")
root.bind("<Enter>",function)
root.geometry("100x100")
B.pack()
root.mainloop()
One way to make this work is to check for event.widget and see if it is the root window, which is a instance of Tk.
import tkinter as tk
root = tk.Tk()
def function(event):
if isinstance(event.widget,tk.Tk): #check if event widget is Tk root window
print("Hello World")
B = tk.Button(root, text ="Label")
root.bind("<Enter>",function)
root.geometry("100x100")
B.pack()
root.mainloop()

How to only close TopLevel window in Python Tkinter?

Use the Python Tkinter , create a sub-panel (TopLevel) to show something and get user input, after user inputed, clicked the "EXIT" found the whole GUI (main panel) also destory.
How to only close the toplevel window?
from tkinter import *
lay=[]
root = Tk()
root.geometry('300x400+100+50')
def exit_btn():
top = lay[0]
top.quit()
top.destroy()
def create():
top = Toplevel()
lay.append(top)
top.title("Main Panel")
top.geometry('500x500+100+450')
msg = Message(top, text="Show on Sub-panel",width=100)
msg.pack()
btn = Button(top,text='EXIT',command=exit_btn)
btn.pack()
Button(root, text="Click me,Create a sub-panel", command=create).pack()
mainloop()
This seemed to work for me:
from tkinter import *
lay=[]
root = Tk()
root.geometry('300x400+100+50')
def create():
top = Toplevel()
lay.append(top)
top.title("Main Panel")
top.geometry('500x500+100+450')
msg = Message(top, text="Show on Sub-panel",width=100)
msg.pack()
def exit_btn():
top.destroy()
top.update()
btn = Button(top,text='EXIT',command=exit_btn)
btn.pack()
Button(root, text="Click me,Create a sub-panel", command=create).pack()
mainloop()
Your only mistake is that you're calling top.quit() in addition to calling top.destroy(). You just need to call top.destroy(). top.quit() will kill mainloop, causing the program to exit.
You can't close to root window. When you will close root window, it is close all window. Because all sub window connected to root window.
You can do hide root window.
Hide method name is withdraw(), you can use show method for deiconify()
# Hide/Unvisible
root.withdraw()
# Show/Visible
root.deiconify()
you can use lambda function with the command it's better than the normal function for your work
ex)
btn = Button(top,text='EXIT',command=exit_btn)
change the exit_btn to lambda :top.destroy()
In my case, I passed a callback function from the parent class, and once the submit button is clicked it will the callback function passing the return values.
The callback function will call the destroy method on the top-level object, thus in that way you'll close the frame and have the return value.

Why does the button move to the current window?

I use the tkinter function to create a new window, it works fine.
When I link from this window to another window, the button moves to the first window. I don't understand why it moves.
Here is the code for the first window,
import tkinter
window = tkinter.Tk()
window.title ("Login")
window.geometry ("300x150")
username = "Gurdip"
password = "1234"
def login():
if txtUser.get() == username and txtPass.get() == password:
import NewWindow
lblUser = tkinter.Label(window, text="Username:")
lblUser.pack()
txtUser = tkinter.Entry(window)
txtUser.pack()
lblPass = tkinter.Label(window, text="Password:")
lblPass.pack()
txtPass = tkinter.Entry(window)
txtPass.pack()
btnenter = tkinter.Button(window, text="Enter", command=login)
btnenter.pack()
And for the second window
import tkinter
window = tkinter.Tk()
window.title ("The Royal Liberty School")
window.geometry ("300x150")
def webpage():
import webbrowser
webbrowser.open("http://www.royalliberty.org.uk/")
lblRlib = tkinter.Label(window, text="Welcome to the Royal Liberty School\n\nClick the link to go to our website")
lblRlib.pack()
def button():
webbutton = tkinter.Button(text ="Royal Liberty School", command = webpage)
webbutton.pack()
button()
My guess is that you're reporting that the "Royal Liberty School" button is appearing on the wrong window, rather than actually moving. I've never heard of a button moving before.
if that guess is correct, it's probably because you aren't giving it an explicit parent, so it's defaulting to the root window.
If all of that code belongs to a single program, you have another problem. You should always only ever create a single instance of Tk. If you need more than one window, create instances of Toplevel.
You are calling both by the name window. This means that there are two windows on the screen both acsessed by the name window. It is more conventional to use tkinter's Toplevel as follows
NewWindow = Toplevel(window)
Then, any items you want to place on this NewWindow, just use it in the place of window
MyButton = Button(NewWindow, text=hi)
As the other answer said, it is incorrect to have to Tk() in one program so you must use the Toplevel.

Categories

Resources