So I'm not new to python or programing in general, but am still learning with python. I am working on a program for me and some of my friends. and I was making the GUI, and code, for the login screen, when I kept getting this syntax error for one of my functions. And I have no idea as to what may be causing it. If someone could provide some assistance it would be greatly appreciated. p.s. I'll only be posting the part I've been having an error with, and only what is, or that I feel, is necessary to help show what's going on, and I'm using python 3.x if that helps.
# Login Setup
loginW = Tk()
# Password Authentication Function
def Authentication():
valid = 'pythonprogramming'
if (pwordE = valid):
# Syntax Error for the above line
mp = Tk()
loginW.destroy()
# Main Program here
mp.mainloop()
else:
errorW = Tk()
errorL = Label(errorW, text='Invalid Password!')
errorW.mainloop()
pwordL = Label(loginW, text='Password: ')
pwordE = Entry(loginW, show='*')
logBtn = Button(loginW, text='Login')
logBtn.bind("<Button-1>", Authentication)
pwordL.pack(row=0)
pwordE.pack(row=0, column=1)
logBtn.pack(row=1, columnspan=2)
loginW.mainloop()
Your code has several errors:
Change pack to grid.
change pwordE = valid to pwordE.get() == valid
add argument event to Authentication function
complete code:
# Login Setup
loginW = Tk()
# Password Authentication Function
def Authentication(event):
valid = 'pythonprogramming'
if pwordE.get() == valid:
# Syntax Error for the above line
mp = Tk()
loginW.destroy()
# Main Program here
mp.mainloop()
else:
errorW = Tk()
errorL = Label(errorW, text='Invalid Password!')
errorL.grid(row=0, column=0)
errorW.mainloop()
pwordL = Label(loginW, text='Password: ')
pwordE = Entry(loginW, show='*')
logBtn = Button(loginW, text='Login')
logBtn.bind("<Button-1>", Authentication)
pwordL.grid(row=0, column=0)
pwordE.grid(row=0, column=1)
logBtn.grid(row=1, columnspan=2)
loginW.mainloop()
Screenshots:
Correct Password:
Incorrect Password:
Related
My tkinter log in screen app has a bug that is when i click the log in button it just show the error.
from tkinter import *
from tkinter import messagebox
login_page = Tk()
login_page.title("login_page")
login_page.geometry("250x110")
def check_pass():
if username == name and userpass == password:
print("this code works")
else :
messagebox.askretrycancel(title="Try again",message="Wrong password ")
# name and password entry
log_name = Entry(login_page)
log_name.grid(row=0, column=1, pady=15)
log_pass = Entry(login_page)
log_pass.grid(row=1, column=1, pady=5)
name_label = Label(login_page, text="Name here:- ")
name_label.grid(row=0, column=0, pady=15)
password_label = Label(login_page, text="Password:- ")
password_label.grid(row=1, column=0, pady=5)
# LOG IN BUTTON
login_btn = Button(login_page, text="LOG IN", command=check_pass)
login_btn.grid(row=2, column=0, columnspan=2, ipadx=100, padx=5)
username = log_name.get()
userpass = log_pass.get()
name = "admin"
password= "admin"
mainloop()
The problem is because the username and the password variables are in the main block and when you run the code the entry boxes are empty(initially) which assigns '' to the variables. So to overcome that you should assign the variables inside the function, where now the values of the filled entry box is only taken.
Code:
from tkinter import *
from tkinter import messagebox
login_page = Tk()
login_page.title("login_page")
login_page.geometry("250x110")
def check_pass():
username = log_name.get()
userpass = log_pass.get()
if username == name and userpass == password:
messagebox.showinfo('Successfull','Login successfull')
else:
choice = messagebox.askretrycancel("Try again","Wrong password ")
if choice == True:
pass
else:
login_page.destroy()
......
# ALL THE SAME LINES OF CODE TILL
name = "admin"
password = "admin"
login_page.mainloop()
Also since your using a messagebox like askretrycancel, you can do certain action based on the choice by the user. So here I have said if the user clicks on retry, then ask them to login again, or else close the application. You can change it to whatever you like(or even remove it too.)
And also it is recommended to say login_page.mainloop(), just so that tkinter isnt confused at any later steps.
Hope your "bug" is cleared and do let me know if any errors :D
Cheers
I have been working on a login page in Tkinter for fun, but I am unable to make a function that checks the entries and compares them to a specific input. Also, the code adds a messagebox and calls a function every time I exit the window.
My code is:
from tkinter import *
from tkinter import messagebox
root = Tk()
root.title("Login")
def makeUname(d):
if messagebox.askyesno("Submit?", "Is this correct?"):
global password
username = uname.get()
uname.grid_forget()
return password
def makePasswd(d):
if messagebox.askyesno("Submit?", "Is this correct?"):
global username
password = uname.get()
passwd.grid_forget()
return username
def button():
makeUname("")
makePasswd("")
quitbutt.grid_forget()
uname = Entry(root)
uname.grid(row=1, column=1)
passwd = Entry(root, show="*")
passwd.grid(row=2, column=1)
quitbutt = Button(root, text="Login", command=button)
quitbutt.grid(row=3, column=1, columnspan=2, sticky='nesw')
root.mainloop()
makeUname("")
makePasswd("")
if(username == "username" and password == "password"):
messagebox.showwarning("Warning", "Sorry, this isn't programmed yet.")
else:
messagebox.showwarning("Nope", "Nope. Nice try.")
Can someone help me with my code? Should I use a different setup or method?
There was many problem so I changed all to make it simpler.
I added comments in code to explain some elements.
from tkinter import *
from tkinter import messagebox
# --- functions ---
def button():
# use global variable (instead of local variables)
# to keep username, password outside function and keep after closing window
global username
global password
username = uname.get()
password = passwd.get()
#print('button:', username, password)
if username == "username" and password == "password":
messagebox.showwarning("Warning", "Sorry, this isn't programmed yet.")
root.destroy() # close window
else:
messagebox.showwarning("Nope", "Nope. Nice try.")
# window still open
# --- main ---
# default values at start
# Someone can exit window without using Button
# and it would not create this variables in button()
username = ""
password = ""
root = Tk()
root.title("Login")
uname = Entry(root)
uname.grid(row=1, column=1)
passwd = Entry(root, show="*")
passwd.grid(row=2, column=1)
quitbutt = Button(root, text="Login", command=button)
quitbutt.grid(row=3, column=1, columnspan=2, sticky='nesw')
# start program (start engine, display window, (re)draw widgets, handle events, get events from system (keyboard, mouse), send events to widgets)
root.mainloop()
# after closing window this variables still have values from window
print("after mainloop:", username, password)
I am working an a tool where-in I am getting the initial user credentials and an unique identifier via Tkinter GUI interface. Post that after a lot of data fetching and processing I would get a report into an excel sheet using xlsxwriter package.
I generally exit/close the tkinter window using destroy() method on click of a button. Here, I want to show the user the status of the report creation in a Tkinter messagebox and then close the main window.
Note: I am using .pyw extension, so that the end user who is using the tool shouldn't see the console. So once the user hits the submit button, I will show a label at the footer of the window saying "Processing ..."
Sample code:
from tkinter import *
#Some other libraries are imported
mScrn = Tk()
mScrn.title("Report Generation Tool v1.0")
mScrn.geometry("200x180")
mScrn.resizable(False, False)
tk_uid_lbl = Label(mScrn, text="MVS1 Username")
tk_uid_lbl.pack()
tk_uid_lbl.place(x=20,y=20)
uid = StringVar()
tk_uid = Entry(mScrn, bd=3, textvariable=uid)
tk_uid.pack()
tk_uid.place(x=150, y=20)
tk_pwd_lbl = Label(mScrn, text="MVS1 Password")
tk_pwd_lbl.pack()
tk_pwd_lbl.place(x=20,y=60)
pwd = StringVar()
tk_pwd = Entry(mScrn, bd=3, show='*', textvariable=pwd)
tk_pwd.pack()
tk_pwd.place(x=150, y=60)
tk_ver_lbl = Label(mScrn, text="Version #")
tk_ver_lbl.pack()
tk_ver_lbl.place(x=20,y=100)
ver = StringVar()
tk_ver=Entry(mScrn, bd=3, textvariable=ver)
tk_ver.pack()
tk_ver.place(x=150, y=100)
tk_sub_button = Button(text='Submit', command = show_footer)
tk_sub_button.pack()
tk_sub_button.place(x=150, y=150)
mScrn.mainloop()
#The data provided in the GUI is used for access and a lot of process goes on
#Close the Tkinter window post the process is done
Thanks in Advance. I am using Python3
I am having a hard time understanding your question. My understanding is that using destroy() is exactly what you are looking for. Use destroy() when you are finished. You basically already answered your own question. I would find it helpful if you could explain your question more thoroughly. I agree with Goyo but I cannot comment.
I don't know how to get the data before closing the mainloop(). In
that aspect once that is closed I cannot show the label on the GUI and
then close with user consent (i.e. after clicking 'ok' in message box)
I don't undestand where is your problem, you can save your data with a lot ways, list, module, object, file, etc.
import tkinter as tk
import random
import threading
import time
# Simulate a process
def get_data(callback):
while True:
if len(data) == 10:
break
time.sleep(.5)
data.append(random.randint(1, 200))
callback()
def wait_end(label, tk_var_end, num=0):
label["text"] = "Processing " + " ." * num
num += 1
if num == 4:
num = 0
if not tk_var_end.get():
mScrn.after(500, wait_end, label, tk_var_end, num)
def execute():
for entry in (tk_uid, tk_pwd, tk_ver):
entry['state'] = tk.DISABLED
tk_sub_button.destroy()
tk_process_lbl = tk.Label(mScrn)
tk_process_lbl.pack()
tk_process_lbl.place(x=150,y=150)
tk_var_end = tk.BooleanVar(False)
wait_end(tk_process_lbl, tk_var_end)
process = threading.Thread(
target=get_data,
kwargs=(dict(callback=lambda: tk_var_end.set(True)))
)
process.start()
mScrn.wait_variable(tk_var_end)
mScrn.after(500, tk_process_lbl.config, dict(text='Process completed'))
mScrn.after(1500, mScrn.quit)
mScrn = tk.Tk()
data = []
mScrn.title("Report Generation Tool v1.0")
mScrn.geometry("400x180")
mScrn.resizable(False, False)
tk_uid_lbl = tk.Label(mScrn, text="MVS1 Username")
tk_uid_lbl.pack()
tk_uid_lbl.place(x=20,y=20)
uid = tk.StringVar()
tk_uid = tk.Entry(mScrn, bd=3, textvariable=uid)
tk_uid.pack()
tk_uid.place(x=150, y=20)
tk_pwd_lbl = tk.Label(mScrn, text="MVS1 Password")
tk_pwd_lbl.pack()
tk_pwd_lbl.place(x=20,y=60)
pwd = tk.StringVar()
tk_pwd = tk.Entry(mScrn, bd=3, show='*', textvariable=pwd)
tk_pwd.pack()
tk_pwd.place(x=150, y=60)
tk_ver_lbl = tk.Label(mScrn, text="Version #")
tk_ver_lbl.pack()
tk_ver_lbl.place(x=20,y=100)
ver = tk.StringVar()
tk_ver= tk.Entry(mScrn, bd=3, textvariable=ver)
tk_ver.pack()
tk_ver.place(x=150, y=100)
tk_sub_button = tk.Button(text='Submit', command = execute)
tk_sub_button.pack()
tk_sub_button.place(x=150, y=150)
mScrn.mainloop()
print(data)
But, you can also make your own class which will inherit of Tk, in this class you could override the quit or destroy method of Tk.
I want to have a login window pop up at first, then once the conditions are satisfied, it closes the login window and opens a new window.
from Tkinter import *
import tkMessageBox
#Not really sure what i'm doing here anymore
while True:
Login = Tk()
Login.title('Login')
Login.geometry('400x130')
NameLabel = Label(Login, text='Username')
NameLabel.place(bordermode=OUTSIDE, height=25, width=100, x=100)
NameEntryRaw = Entry(Login)
NameEntryRaw.place(bordermode=OUTSIDE, height=25, width=100, x=200)
CodeLabel = Label(Login, text='Code')
CodeLabel.place(bordermode=OUTSIDE, height=25, width=100, x=100, y=30)
CodeEntryRaw = Entry(Login)
CodeEntryRaw.place(bordermode=OUTSIDE, height=25, width=100, x=200, y=30)
def tbd():
tkMessageBox.showinfo('Congrats!', 'This program is not done yet')
def login():
Usernames=list()
Usernames.append('Mordecai')
Usernames.append('Ezekiel')
Usernames.append('Goliath')
Usernames.append('Abraham')
Usernames.append('Bartholomew')
Usernames.append('Jedediah')
Usernames.append('Solomon')
Usernames.append('Tobias')
Usernames.append('Yohanan')
Usernames.append('Lucifer')
NameEntry=NameEntryRaw.get()
CodeEntry=CodeEntryRaw.get()
CodeReal='116987'
if Usernames.count(NameEntry) == 0:
tkMessageBox.showinfo('Error!', 'Your Username is invalid! Try Again.')
else:
()
if CodeEntry != CodeReal:
tkMessageBox.showinfo('Error!', 'The Code entered is invalid! Try Again.')
else:
()
LoginButton = Button(Login, text="Login", command=login)
LoginButton.place(bordermode=OUTSIDE, height=50, width=200, x=100, y=60)
Login.mainloop()
else:
DataBase = Tk()
#this will be the data base
DataBase.mainloop()
You don't want to use two mainloop's. Generally speaking, your tkinter app should have a single .mainloop called.
As for how to get the login popup and then switch to the window... You can create your root window with the app and when you start your program have a Toplevel window be shown with the login stuff, maybe hide / withdraw the root additionally?, have the toplevel have a submit button or something that would validate the credentials. If the credentials are valid, then you can use the destroy() method and remove the toplevel widget / go to the root window for your main app.
Having a while True repeat the process of creating a GUI + mainloop is bad for obvious reasons.
Edit: static is probably a bad term for a mutable object, since it's mutable... Added tuple vs list for global.
You don't need to create a blank list and then use append to add your usernames to the usernames list. You can make this global. Since, username is a mutable object (it's a list) you could still perform operations elsewhere in your code on this global, say .append etc. Or, if you never have these change i'd make it a tuple, since they're immutable and this "fits" better with the intent.
Instead of using .count(*) to get the occurrences of an element in a list you can just use:
if (object) in (some list) #Object is an abstraction, not the type
If CodeReal is static, which it looks to be, you can also make this global.
Here's a quick edit to your code, you can do this without classes, but I used classes here to try to distinctly show the logical separation in the program.
I changed a few variable names as well, so that it was easier to read / understand. I also used .pack() and .grid() as this was quicker to code than having to use .place() everywhere this is an arbitrary choice.
import Tkinter as tk
import tkMessageBox as messagebox
import sys
#No need to do usernames = list() and then .append for each one.
#Just make a global list holding them all...
USERNAMES = ('Mordecai', 'Ezekiel', 'Goliath', 'Abraham', 'Bartholomew',
'Jedediah', 'Solomon', 'Tobias', 'Yohanan', 'Lucifer')
PASSWORD = '116987' #Was CodeReal, this can be global
#We overrode the closing protocol here.
def closing_protocol():
if messagebox.askokcancel("Quit", "Do you want to quit?"):
sys.exit()
#A container for our Login "app".
class Login(tk.Toplevel):
def __init__(self, *args, **kwargs):
#We init the toplevel widget.
tk.Toplevel.__init__(self, *args, **kwargs)
#We set the closing protocol to be the overridden version / func.
self.wm_protocol("WM_DELETE_WINDOW", closing_protocol)
tk.Label(self, text='Username').grid(row=0, column=0)
self.username = tk.Entry(self)
self.username.grid(row=0, column=1)
tk.Label(self, text='Password').grid(row=1, column=0)
#Show = '*' just hides the password instead of plain-text like
#you typically see
self.password = tk.Entry(self, text='Password', show='*')
self.password.grid(row=1, column=1)
#When the button is clicked the _callback function will be called
tk.Button(self, text='Login', command=self._callback).\
grid(row=2, column=0, columnspan=2, sticky="nsew")
def _callback(self):
#If the username or password is bad, raise an error message.
if (self.username.get() not in USERNAMES or
self.password.get() != PASSWORD):
messagebox.showerror("Validation Error!",
"You have entered invalid credentials.\n" +
"Please try again.")
#otherwise, we're good to go. Destroy login / show main app.
else:
root.deiconify()
app.pack()
self.destroy()
class Main(tk.Frame):
def __init__(self, master):
tk.Frame.__init__(self, master)
tk.Label(self, text="MAIN APP STUFF").pack()
if __name__ == '__main__':
root = tk.Tk()
root.withdraw() #Hides the root window initially.
app = Main(root)
Login()
root.mainloop()
I want to thank you for clarifying what you did for me. It proved to be very helpful! Here is what I've settled with. I put the names back and made it to work without classes, as I found it a little too difficult to work with.
from Tkinter import *
import tkMessageBox
import sys
import binascii #Not for this part
Codenames = ['Mordecai', 'Ezekiel', 'Goliath', 'Abraham', 'Bartholomew',
'Jedediah', 'Solomon', 'Tobias', 'Yohanan', 'Lucifer']
Password = '116987'
def close_protocol():
if tkMessageBox.askokcancel("Quit", "Do you want to quit?"):
sys.exit()
#Below for a later part...
def text_to_bits(text, encoding='utf-8', errors='surrogatepass'):
bits = bin(int(binascii.hexlify(text.encode(encoding, errors)), 16))[2:]
return bits.zfill(8 * ((len(bits) + 7) // 8))
def text_from_bits(bits, encoding='utf-8', errors='surrogatepass'):
n = int(bits, 2)
return int2bytes(n).decode(encoding, errors)
def int2bytes(i):
hex_string = '%x' % i
n = len(hex_string)
return binascii.unhexlify(hex_string.zfill(n + (n & 1)))
#Above for a later part...
SDB = Tk()
SDB.title("SMEGJALBYT DATA BASE")
SDB.withdraw()
SDBLogin = Toplevel()
SDBLogin.title("Login")
SDBLogin.wm_protocol("WM_DELETE_WINDOW", close_protocol)
CodenameLabel = Label(SDBLogin, text="Codename")
CodenameLabel.grid(row=0, column=0)
CodenameEntry = Entry(SDBLogin)
CodenameEntry.grid(row=0, column=2)
PasswordLabel = Label(SDBLogin, text="Password")
PasswordLabel.grid(row=1, column=0)
PasswordEntry = Entry(SDBLogin, show='*')
PasswordEntry.grid(row=1, column=2)
def login_operation():
if CodenameEntry.get() not in Codenames:
tkMessageBox.showinfo("INVALID CODENAME!", "Please verify input in the 'Codename' field")
elif PasswordEntry.get() != Password:
tkMessageBox.showinfo("INVALID PASSWORD!", "Please verify input in the 'Password' field")
else:
SDB.deiconify()
SDBLogin.destroy()
LoginButton = Button(SDBLogin, text="Login", command=login_operation)
LoginButton.grid(row=2, column=1)
#Code continues...
#Code finisles....
SDB.mainloop()
This has the same basic functionality, just organised the way I wanted it.
so im making a simple log in and sign up page and all is going well until i try to get my variables from my definition for my sign up page. Python says it is an unresolved reference that should resolve the typing matches and all but maybe somebody can help. Also i know there is a easier way to add pages by using classes but i i decided to do it this way. Thanks ahead of time. p.s the error is in the sign_up_check() code which the variables are gotten from the sign_up() definition.
import tkinter
# window set up
window = tkinter.Tk()
window.geometry("300x200")
window.title("Game")
window.configure(bg="grey26")
# username label
lbl = tkinter.Label(window, text="username", bg="gold")
enter_username = tkinter.Entry(window, bg="indian red1")
lbl.pack()
enter_username.pack()
# password setup
label_password = tkinter.Label(window, text="password", bg="gold")
enter_password = tkinter.Entry(window, bg="indian red1")
label_password.pack()
enter_password.pack()
# sign in
def log_in():
username = enter_username.get()
password = enter_password.get()
if len(username) > 0 and len(password) > 0:
print("it passed")
else:
print("Log in error: Double check username and password")
def sign_up_check():
# init vars
username = signup_username.get()
password = signup_pasword.get()
age = signup_age.get()
# check if vars greater than one
if len(username) > 0 and len(password) > 0 and age > 0:
print("this all passed")
else:
print("all else failed")
def sign_up():
# create new window
window1 = tkinter.Toplevel()
window1.geometry("300x200")
window1.title("Sign up")
window1.configure(bg="grey26")
# create buttons and labels
# username
label_sign_up = tkinter.Label(window1, text="Enter new username", bg="indian red1")
signup_username = tkinter.Entry(window1, bg="gold")
label_sign_up.pack()
signup_username.pack()
# password
label_sign_up_password = tkinter.Label(window1, text="Enter new password", bg="indian red1")
signup_password = tkinter.Entry(window1, bg="gold")
label_sign_up_password.pack()
signup_password.pack()
# age
label_enter_age = tkinter.Label(window1, text="Enter your age", bg="indian red1")
signup_age = tkinter.Entry(window1, bg="gold")
label_enter_age.pack()
signup_age.pack()
# confirm account
button_account = tkinter.Button(window1, text="Create account", bg="red", command=lambda: sign_up_check())
button_account.pack()
# log in button set up
button_login = tkinter.Button(window, text="Log in", bg="gold", command=lambda: log_in())
button_login.pack()
# sign up button
button_signup = tkinter.Button(window, text="Sign up", bg="gold", command=lambda: sign_up())
button_signup.pack()
window.mainloop()
The main reason for your behavior is that the locally defined variables from your functions are in a local scope.
That means that they are only available in your local function, not outside of it.
Like martineau pointed out, you have a typo in password in function sign_up_check.
Using global Variables:
to make this work every widget that is created inside a function needs to be created globally.
def login():
global enter_username, enter_password
# [... The rest of the code ...]
def sign_up_check():
global signup_username, signup_password, signup_age
# [... The rest of the code ...]
Is there any specific and programmatically relevant reason why you do not want to use classes?
To be honest with you, i do not see any advantage in using global variables and procedural programming in coding Graphical User Interfaces especially with python.
I highly recommend an object oriented programming style here to improve maintenance of code and reduce the amount of redundant coding (global declaration at beginning, global usage in every function, etc...).