How to close other window by python Tkinter? - python

I have following python code in Tkinter.
import tkinter as tk
def main_gui(login, s):
login.quit() # close login window
win = tk.Tk()
win.geometry('300x150')
name = tk.Label(win, text='Hello' + s.get()) # Hello David
name.pack()
win.mainloop()
# initial Tkinter frame
login = tk.Tk()
login.title('Login')
login.geometry('300x150')
# input user name
user_name_var = tk.StringVar()
user_name_var.set('David')
tk.Label(login, text='User name').place(x=10, y=50)
user_name = tk.Entry(login, textvariable=user_name_var)
user_name.place(x=100, y=50)
input_ok = tk.Button(win_login, command=lambda: main_gui(login, user_name), text='OK', width=15)
input_ok.place(x=100, y=90)
win_login.mainloop()
I want to close login window, but my code can not close it. How to solve it.

You are almost there - only two details you have to adapt:
The method to remove a widget in Tkinter is destroy, so login.quit() should be login.destroy().
Once login is destroyed, the user_name Entry will also be destroyed, and you will not be able to get the name from it anymore. You should get the name earlier, e.g., directly in the lambda:
... lambda: main_gui(login, user_name.get()), ...

you can use the
root.withdraw()
function, this will close the window without completely destroying all of the root.after functions

Related

Python tkinter kept saying my variable to hold the .get() value is not defined

I am learning how to use the .get() for tkinter, and trying to write this basic GUI that can store, process, and display data depending on a user input.
Now (I am fairly new to this, so I am probably wrong) to my knowledge, I need to use the .get() and store it into a variable for future uses.
Now here are my codes, but when I run the code, it kept saying I did not define my variable in the function I defined.
I wrote in Pycharm, the variable I wrote in the first line of the function just keep turning grey.
Why is this happening, am I missing something important?
Sidenote:
I have done some research and saw some result regarding using the following method:
StringVar()
fstring, f"{}"
but I still can't figure out how that works and how it is affecting my code that Python is not accepting my variable.
Import tkinter as tk
def event():
expEntry = entry.get()
window = tk.Tk()
entry = tk.Entry(window)
button = tk.Button(window,commnad=event())
expEntry = tk.Label(window,text = expEntry)
entry.pack()
button.pack()
expEntry.pack()
window.mainloop()
You should use a StringVar to store the value of the entry when event() is called by button
import tkinter as tk
def event(): # use this function to update the StringVar
entry_content = entry.get()
entry_var.set(entry_content)
window = tk.Tk()
# declare a StringVar to store the value of your Entry and update your Label
entry_var = tk.StringVar(window, 'Default Text')
# use 'textvariable' here to update the label when the bound variable changes
expEntry = tk.Label(window, textvariable=entry_var)
entry = tk.Entry(window)
# there was a typo in 'command' here, FIY
button = tk.Button(window, text='Press me', command=event)
entry.pack()
button.pack()
expEntry.pack()
window.mainloop()
Note: you don't need the () for the command binding, as you're not calling the event function there! You're just telling the button the name of the function it should call.
Easier way to do this. Just added tk.StringVar().
import tkinter as tk
window = tk.Tk()
window.geometry("700x300")
window.title("StringVar Object in Entry Widget")
var =tk.StringVar(window)
def event():
Label2.config(text=var.get())
myEntry = tk.Entry(window, textvariable=var)
myEntry.pack()
myButton = tk.Button(window, text="Submit", command=event)
myButton.pack()
Label2 = tk.Label(window, font="Calibri,10")
Label2.pack()
window.mainloop()
Output before:
Output after:

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.

How to close top level tkinter window with a button, if button in the window already is bound to a function

I'm somewhat new to tkinter and Python and am working on a semester long project. Basically I have a main tkinter window, then from that window, topLevel windows are called depending on the user input. In the each topLevel window I have a button that performs a function, I also want this button to close the topLevel window after performing that function. What would be the best way to approach this problem?
I have tried to destroy or close the window, but it ends up closing the main window also. I am just looking for a way to close the topLevel window and perform the function with the click of a button
class MainWindow:
# Entry box
self.entry = StringVar()
self.text_box = Entry(master, textvariable=self.entry)
self.text_box.grid(row=1, column=2)
# Displays and binds button, so when clicked, the enter_button function is called
self.input_button = Button(master, text='Enter', command=self.enter_button)
self.input_button.grid(row=1, column=3, sticky='W')
def enter_button(self):
# Get user input and perform the given command
command = self.entry.get()
# Creates a root for a toplevel window
top = Toplevel()
if command == '1':
add_gui = AddPayment(top)
top.mainloop()
elif command == '2':
#rest of classes/commands
main
def main():
root = Tk()
app = MainWindow(root)
root.mainloop()
if __name__ == '__main__':
main()
AddPayment class
class AddPayment:
def __init__(self,master):
self.master = master
self.add_label = Label(master, text='How much is the payment for?')
# payment box
self.pay = StringVar()
self.pay_box = Entry(master, textvariable=self.pay)
self.add_button = Button(master, text='Add', command=self.add_payment)
# position widgets
self.pay_box.grid(row=1, column=2)
self.add_label.grid(row=1, column=1)
self.add_button.grid(row=1, column=3)
def add_payment(self):
database.add_pay(self.pay.get())
In this example I would like something in the add_payment function to close the topLevel window after the add_pay function is performed somehow. Thanks in advance
You have a couple problems. For one, you should never call mainloop more than once. You need to remove the call to mainloop() from the enter_button function.
The other problem is that you're not saving a reference to the toplevel, so you've made it more-or-less impossible to destroy it. You simply need to save a reference and then call destroy on the reference.
self.top = Toplevel()
...
self.top.destroy()

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