I created a library management system with GUI and want to add a login GUI on it as well. What I want in the login window to pop up first and then, if the credentials are right, the management system opens up.
The problem I'm facing is that when I hit the login button, the management system opens but the login window also stays there. I have tried self.root.destroy() before creating the window for management system but it closes all the windows and the management system also shuts down.`
What can I do?
class login_system():
def __init__(self, root):
self.root = root
self.root.title('Login')
self.root.geometry('500x250')
self.root.config(background='black')
self.loggedin = False
user = Label(root, text='Username:', font=('times new roman',20, 'bold'), fg='white', bg='black', padx=15,pady=10)
user.grid(row=0, column=0, padx=10, pady=10)
password = Label(root, text='Password:', font=('times new roman',20, 'bold'), fg='white', bg='black', padx=15 )
password.grid(row=1, column=0, padx=10, pady=10)
self.user_var= StringVar()
self.pass_var= StringVar()
user_ent = Entry(root, width=20, font=('times new roman',18, 'bold'),textvariable=self.user_var)
user_ent.grid(row=0, column=1)
pass_ent = Entry(root, width=20,font=('times new roman',18, 'bold'),textvariable=self.pass_var)
pass_ent.grid(row=1, column=1)
submit = Button(root, text='Login', command=self.login,font=('times new roman',18, 'bold'))
submit.grid(row=3, column=1, pady=10)
def login(self):
userinfo = self.user_var.get()
passinfo= self.pass_var.get()
conn = mysql.connector.connect(host='localhost', username='root', password = 'testpass', database = 'librarydb')
my_cursor = conn.cursor()
my_cursor.execute('SELECT username, password FROM login_system')
rows = my_cursor.fetchall()
conn.close()
for row in rows:
if row[0] ==userinfo:
if row[1]==passinfo:
tmsg.showinfo('Successful!', 'Logged In')
self.loggedin=True
self.newWindow= Toplevel(self.root)
self.app = LibraryManagementSystem(self.newWindow)
else:
tmsg.showinfo('Incorrect', 'Incorrect Password. Please try again')
break
else:
tmsg.showinfo('Incorrect', 'Incorrect username. Please try again')
break
class LibraryManagementSystem():
def __init__(self, root):
self.root= root
self.root.title('Library Management System')
self.root.geometry('1366x768')
When you destroy() the login window, all of the other windows are destroyed as well because it is the root window. To avoid this, the login window needs to be a Toplevel, not Tk.
You can create the root window like this:
root = Tk()
root.iconify()
login_system(root)
root.iconify() hides the root window, but it's still there so the other windows don't close. Then inside of the login class you need to create a Toplevel like this:
class login_system():
def __init__(self, root):
self.root = root
self.login_window = Toplevel(self.root)
self.login_window.title('Login')
self.login_window.geometry('500x250')
self.login_window.config(background='black')
...
This is similar to how you made the window for the managment system after the user has logged in.
After the new window is created, you need to destroy the login one like this:
self.newWindow= Toplevel(self.root)
self.app = LibraryManagementSystem(self.newWindow)
self.login_window.destroy() #This bit is new
Then it will all work as expected.
Here, you can use .withdraw method. This will hide the main window without destroying the whole application. So, you can get your Toplevel() and hide the original window
self.root.withdraw()
This will hide the main window without destroying it.
And, after you are done, and you want to show the login window,
self.root.deiconify()
This will make to hidden window to be revealed.
Related
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()
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
Preface:
I have a Python ControlGPIO code with a working GUI (let us call it MainGUI).
I wish to have a dialog pop up window, prior to running MainGUI, in a way that the user can enable/ disable features in MainGUI. BUT MainGUI should start running only after dialog pop up window is closed.
My question is: How can I make a popup window that will postpone MainGUI untill it is closed?
Code below- boot_windows is my dialog pop up window (where all the enable/disable checkboxes will be ), BUT obviously does not postpone App as I need
root = Tk()
#output_gpioPins = [4,22,6,26]
#input_gpioPins = [3,21,5,27]
#ip = '192.168.2.112'
boot_windows = Toplevel(root)
text1 = ttk.Label(boot_windows, text="Hello World !!!")
text1.grid()
App = ContorlGPIOWindow(root, ip = '192.168.2.113', with_sf_bt=1, with_hw_bt=1, switch_names=['Light Kitchen','Light Room1', 'Window1', 'Window2'])
root.mainloop()
You can't do precisely what you want. Widgets exist in a tree-like structure. All windows except the root require a root window. The root window must be created first (which is why it's called the root window).
If you don't want the user to see it, you can hide it until it is ready to be displayed.
import tkinter as tk
root = tk.Tk()
root.withdraw()
boot_window = tk.Toplevel(...)
...
You can then call root.deiconify() when you are ready for it to be visible.
Another common solution is to use the root window for your dialog or splash screen or whatever, and then simply replace its contents with the real contents when you're ready.
As for how to wait for the popup... the root window has a method named wait_window which will enter the event loop and not return until the given window has been destroyed.
Here's an example of it's use:
import Tkinter as tk
class MainGUI(tk.Frame):
def __init__(self, parent):
tk.Frame.__init__(self, parent)
label = tk.Label(self, text="Hello, world!")
label.pack(fill="both", expand=True, padx=20, pady=20)
class Popup(tk.Toplevel):
def __init__(self, root):
tk.Toplevel.__init__(self, root)
label = tk.Label(self, text="Click to continue...")
label.pack(fill="both", expand=True, padx=20, pady=20)
button = tk.Button(self, text="OK", command=self.destroy)
button.pack(side="bottom")
if __name__ == "__main__":
root = tk.Tk()
root.withdraw()
popup = Popup(root)
root.wait_window(popup)
main = MainGUI(root)
main.pack(fill="both", expand=True)
root.deiconify()
root.mainloop()
This is ui which comes with default user name and password but after successful login the main UI needs to appear
Challenge
when you correctly input the user name and password the main window doesn't open but rather when you click cancel or close button then it opens
Finding solution
Main window should appear after successfully login with the default password and user name
from tkinter import *
from tkinter import ttk
from tkinter import messagebox
def try_login(): # this my login function
if name_entry.get()==default_name and password_entry.get() ==
default_password:
messagebox.showinfo("LOGIN SUCCESSFULLY","WELCOME")
else:
messagebox.showwarning("login failed","Please try again" )
def cancel_login(): # exit function
log.destroy()
default_name=("user") #DEFAULT LOGIN ENTRY
default_password=("py36")
log=Tk() #this login ui
log.title("ADMIN-LOGIN")
log.geometry("400x400+400+200")
log.resizable (width=FALSE,height=FALSE)
LABEL_1 = Label(log,text="USER NAME")
LABEL_1.place(x=50,y=100)
LABEL_2 = Label(log,text="PASSWORD")
LABEL_2.place(x=50,y=150)
BUTTON_1=ttk. Button(text="login",command=try_login)
BUTTON_1.place(x=50,y=200)
BUTTON_1=ttk. Button(text="cancel",command=cancel_login)
BUTTON_1.place(x=200,y=200)
name_entry=Entry(log,width=30)
name_entry.place(x=150,y=100)
password_entry=ttk. Entry(log,width=30,show="*")
password_entry.place(x=150,y=150)
log. mainloop()
MAIN_WINDOW=Tk() #after successful this main ui should appear
MAIN_WINDOW.geometry("600x500+300+100")
MENU_1 = Menu(MAIN_WINDOW)
MAIN_WINDOW.config(menu=MENU_1)
SETTINGS_1 = Menu(MENU_1,tearoff=0)
MENU_1.add_cascade(label="SETTINGS",menu=SETTINGS_1,underline=0)
SETTINGS_1.add_command(label="Change Password")
MAIN_WINDOW. mainloop()
I would appreciate if the answers comes in functions as am newbie in python and programming in general
The below code can be used for the desired effect and is commented to show what is happening each step of the way:
from tkinter import * #Imports Tkinter
import sys #Imports sys, used to end the program later
root=Tk() #Declares root as the tkinter main window
top = Toplevel() #Creates the toplevel window
entry1 = Entry(top) #Username entry
entry2 = Entry(top) #Password entry
button1 = Button(top, text="Login", command=lambda:command1()) #Login button
button2 = Button(top, text="Cancel", command=lambda:command2()) #Cancel button
label1 = Label(root, text="This is your main window and you can input anything you want here")
def command1():
if entry1.get() == "user" and entry2.get() == "password": #Checks whether username and password are correct
root.deiconify() #Unhides the root window
top.destroy() #Removes the toplevel window
def command2():
top.destroy() #Removes the toplevel window
root.destroy() #Removes the hidden root window
sys.exit() #Ends the script
entry1.pack() #These pack the elements, this includes the items for the main window
entry2.pack()
button1.pack()
button2.pack()
label1.pack()
root.withdraw() #This hides the main window, it's still present it just can't be seen or interacted with
root.mainloop() #Starts the event loop for the main window
This makes use of the Toplevel widget in order to create a window which asks for the users details and then directs them to the main window which you can setup as you please.
You are also still able to use the pop up messages you have used in your example and if required you can also change the size of the Toplevel widget.
Please be advised however that this is not a particularly secure way of managing passwords and logins. As such I would suggest that you look up the proper etiquette for handling sensitive information in programming.
I am starting by making a simple prompt window where the user will fill out the name of the directory to grab images from and where to save a resultant .csv file (and some other info).
After pressing enter in this (in this case) I want this prompt window to close and the main window where all the work will be performed by the user to appear.
In short, is this the correct way to begin structuring the classes for my GUI? Also why does the line:
frame = Frame(master, height=500,padx=20, pady=20)
Not change the formatting/layout of this initial window?
I feel that once i have a solid grasp on how to build this initial window, I will have the proper foundation to continue the rest on my own.
#imports
from Tkinter import *
import glob
from PIL import Image, ImageTk
#end imports
class prompt_window:
def __init__(self, master):
frame = Frame(master, height=500,padx=20, pady=20)
#Build prompt window labels
self.source_label = Label(root, text="Source Directory")
self.destination_label = Label(root, text="Destination Directory")
self.region_sz_label = Label(root, text="Region Size")
self.save_file_name_label = Label(root, text="Save File Name")
#Build prompt window entry forms
self.source_entry = Entry(root)
self.destination_entry = Entry(root)
self.region_sz_entry = Entry(root)
self.save_file_name_entry = Entry(root)
#Build enter button
self.enter_button = Button(root, text="Enter")
#Align labels in prompt window grid
self.source_label.grid(row=0)
self.destination_label.grid(row=1)
self.region_sz_label.grid(row=2)
self.save_file_name_label.grid(row=3)
#Align entry forms in prompt window grid
self.source_entry.grid(row=0, column=1)
self.destination_entry.grid(row=1, column=1)
self.region_sz_entry.grid(row=2, column=1)
self.save_file_name_entry.grid(row=3, column=1)
#Add button
self.enter_button.grid(row=4,column=2)
#create root
root = Tk()
#create prompt window
prompt = prompt_window(root)
#run indefinitely
root.mainloop()
You need to call one of the layout methods (.pack, .grid, or .place) on your Frame to make it visible. In my version of your program I've changed the class name from prompt_window to PromptWindow to conform to the PEP-8 style guide. I've also changed the Tkinter import statement so we aren't cluttering our namespace with all those Tkinter names.
Organizing GUI code is a little different to organizing a plain CLI program. Once we've defined everything we sit in a loop waiting for events to respond to. So for this program we need to set things up so that when the prompt window closes the main window opens and it has access to the data gathered by the prompt window.
You said that you want the prompt window to be a different window to the main window, so we need to create a window for it. A Tkinter program can only have one root window, so we create a Toplevel window to hold the prompt Frame.
You don't need to save the Labels as attributes of the PromptWindow instance since you aren't doing anything with them after you create them.
I've changed the Entry widgets slightly: I've given each of them a StringVar to hold their data. This makes it possible to access that data after the prompt window is closed. When a widget's parent window is closed you can't access it anymore. So instead of saving each Entry as an attribute of PromptWindow we instead save the associated StringVar.
When the "Enter" button is pressed or the prompt window's close widget is pressed we close the prompt window and make the main window visible.
I've created a simple MainWindow class that contains a button that lets us print the data gathered by the prompt window.
import Tkinter as tk
class PromptWindow(object):
def __init__(self, master):
self.master = master
self.win = tk.Toplevel(master)
self.win.title("Prompt Window")
# Intercept close window events so that when the user closes this window
# (via the close widget or the Enter button) the main window reopens
self.win.protocol("WM_DELETE_WINDOW", self.close)
frame = tk.Frame(self.win, height=500,padx=20, pady=20)
frame.pack()
# Build prompt window labels
tk.Label(frame, text="Source Directory").grid(row=0)
tk.Label(frame, text="Destination Directory").grid(row=1)
tk.Label(frame, text="Region Size").grid(row=2)
tk.Label(frame, text="Save File Name").grid(row=3)
# Build prompt window entry widgets
self.source = tk.StringVar()
tk.Entry(frame, textvariable=self.source).grid(row=0, column=1)
self.destination = tk.StringVar()
tk.Entry(frame, textvariable=self.destination).grid(row=1, column=1)
self.region_sz = tk.StringVar()
tk.Entry(frame, textvariable=self.region_sz).grid(row=2, column=1)
self.save_file_name = tk.StringVar()
tk.Entry(frame, textvariable=self.save_file_name).grid(row=3, column=1)
# Build enter button
tk.Button(frame, text="Enter", command=self.close).grid(row=4,column=2)
def close(self):
# Close this window
self.win.destroy()
# Reopen the main window
self.master.deiconify()
class MainWindow(object):
def __init__(self):
# Create root window
root = tk.Tk()
# and make it invisible
root.withdraw()
root.title("Main Window")
# Add some widgets
tk.Label(root, text="This is the main window").pack()
tk.Button(root, text="Show data", command=self.show_data).pack()
# Create prompt window
self.prompt = PromptWindow(root)
# Loop forever
root.mainloop()
# Display the data gathered by the prompt window
def show_data(self):
prompt = self.prompt
src = prompt.source.get()
dest = prompt.destination.get()
region = prompt.region_sz.get()
fname = prompt.save_file_name.get()
fmt = 'src: {!r}, dest: {!r}, region: {!r}, fname: {!r}'
print(fmt.format(src, dest, region, fname))
MainWindow()