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...).
Related
I'm very new. Haven't gotten to "Classes" yet. Just trying to understand functions before I move forward. Trying to make a basic login widget that when the register button is clicked, it destroys the root window, launches the register window, then once the submit button is clicked, it gets the entry info and for right now, just prints it. I have one file that works but only has one Tk() window. Once you add another like the register function, the code no longer works. I figure it must be the order of operation that I am not understanding the concept of so I wanted some help. I have even tried to put the variables, "username_var, password_var into the register function since they are originally outside of the function but that didn't work either. Also tried calling global variables inside the register function but no luck there either. I worked on this for two days, so please don't think I didn't try all I could on my own. If you know of any documentation that I could read to better understand this, please let me know. I couldn't find anything on this topic.
from tkinter import *
# The first widget/container, not resizable
root = Tk()
root.resizable(False, False)
# variables to store the usernames and passwords
username_var = StringVar()
password_var = StringVar()
password2_var = StringVar()
''' Submit logic, if submit button is clicked or enter is pressed and username does not exist in variable list user_name and both password entries match, save username and password in variable list. '''
def submit():
print('Your username is ' + username_var.get())
if password_var == password2_var:
print('Your password is ' + password_var.get())
else:
print('Passwords do not match')
''' register button logic(if register button is clicked, destroy root window, load register window. Register window will have one username and two password labels and entries, entries have textvariables, rw = register window '''
def register_user():
root.destroy()
register_window = Tk()
rw_user_label = Label(register_window, text='Username')
rw_user_label.grid(row=0, column=0)
rw_pass_label = Label(register_window, text='Password')
rw_pass_label.grid(row=1, column=0)
rw_pass_label = Label(register_window, text='Password')
rw_pass_label.grid(row=2, column=0)
rw_user_entry = Entry(register_window, textvariable=username_var)
rw_user_entry.grid(row=0, column=1)
rw_pass_entry = Entry(register_window, textvariable=password_var, show='*')
rw_pass_entry.grid(row=1, column=1)
rw_pass_entry2 = Entry(register_window, textvariable=password2_var, show='*')
rw_pass_entry2.grid(row=2, column=1)
submit_button = Button(register_window, text='Submit', command=submit)
submit_button.grid(row=3, column=1, sticky='ew')
# username and password labels with grid locations
user_label = Label(root, text='Username')
user_label.grid(row=0, column=0)
pass_label = Label(root, text='Password')
pass_label.grid(row=1, column=0)
# username and password entries with grid locations
user_entry = Entry(root)
user_entry.grid(row=0, column=1)
pass_entry = Entry(root, show='*')
pass_entry.grid(row=1, column=1)
# Login and Register buttons with grid locations, both call functions
login_button = Button(root, text='Login')
login_button.grid(row=2, column=1, sticky='ew')
register_button = Button(root, text='Register', command=register_user)
register_button.grid(row=3, column=1, sticky='ew')
# creates an infinite loop for main root widget until destroy function is called or the widget is exited out of
root.mainloop()
In the register function the entry textvariables are used as initial values to be placed as default in this code. Any changes to the textvariables in the entry don't happen unless they have been declared global inside register.
def register():
global username_var, password_var, password2_var
so you are on the right track in terms of thinking about scope - a global variable has to be specified as global if it is changed inside a function scope. Otherwise it is simply referenced.
Another late night project. I was trying to make a simple login screen (the credentials will be used later).
Now I want to store the username and password as the variables USERNAME and PASSWORD in the "login screen".
For some reason it doesnt work. I tried so many things, like 'global', 'return' etc.
Is there a way to store the inputs in those variables without changing the code dramasticly? I will be modifying the code later on quite a bit and need to understand and explain this too numerous people.
EDIT:
in the dropdown menu there is a option called "-------". I never put it there, but it keeps popping up. Is there a reason why it always pops up? And how can I delete it?
import os
import smtplib
from tkinter import *
import tkinter.messagebox
#USERNAME
#PASSWORD
root = Tk()
root.geometry("500x300")
root.title("E-mail-Sending program EBF")
# *** FUNCTIONS ***
def setLoginCredentials():
USERNAME = entryLoginUsername.get()
PASSWORD = entryLoginPassword.get()
print(USERNAME)
print(PASSWORD)
def loginCredentials(event):
#Create another screen
loginScreen = Toplevel(root)
loginScreen.title("login-screen")
loginScreen.geometry("300x300")
#LABELS LOGIN SCREEN
labelLoginUsername = Label(loginScreen, text="E-mail:")
labelLoginUsername.grid(row=0,column=0, sticky=E)
labelLoginPassword = Label(loginScreen, text="Password:")
labelLoginPassword.grid(row=1,column=0, sticky=E)
#ENTRIES LOGIN SCREEN
entryLoginUsername = Entry(loginScreen)
entryLoginUsername.grid(row=0,column=1)
entryLoginPassword = Entry(loginScreen)
entryLoginPassword.grid(row=1,column=1)
#LOGIN BUTTON
loginButton1 = Button(loginScreen,text="Login",command=setLoginCredentials)
# loginButton1.bind("<Button-1>", setLoginCredentials)
loginButton1.grid(row=2,column=1, sticky=W)
def previewEmail():
tkinter.messagebox.showinfo('Email preview','Dear professor <NAME>\n\n\nThis email is on behalf of the Academy Committee of EBF Groningen, which is responsible for the booksale of the Economics and Business Faculty of the University of Groningen.\n\nSince you are the coordinator of the course <NAME>, we were wondering if any alterations were made regarding the compulsory literature that has not been listed on the latest version of Ocasys yet.\n\nWe would like the confirmation if the course literature on Ocasys is up to date or if any alterations are needed. This way we are able to contact the suppliers of these books and ensure that inconveniences, due to providing the wrong books, can be avoided.\n\n\nMet vriendelijke groet,\nKind Regard,\n\n<SENDER> - <FUNCTION>\nAcademy Committee\nEBF Groningen\n')
# *** LABELS HOMESCREEN ***
labelSender = Label(root, text="Sender:")
labelSender.grid(row=0,column=0, sticky=E)
labelFunction = Label(root, text="Function:")
labelFunction.grid(row=1,column=0, sticky=E)
labelEmail = Label(root, text="Email:")
labelEmail.grid(row=2,column=0, sticky=E)
labelProfessor = Label(root, text="Professor:")
labelProfessor.grid(row=3,column=0, sticky=E)
labelCourse = Label(root, text="Course:")
labelCourse.grid(row=4,column=0, sticky=E)
# *** ENTRIES MAINSCREEN***
entrySender = Entry(root)
entrySender.grid(row=0,column=2, columnspan=2)
entryFunction = Entry(root)
entryFunction.grid(row=1,column=2, columnspan=2)
entryEmail = Entry(root)
entryEmail.grid(row=2,column=2, columnspan=2)
entryProfessor = Entry(root)
entryProfessor.grid(row=3,column=2, columnspan=2)
entryCourse = Entry(root)
entryCourse.grid(row=4,column=2, columnspan=2)
# *** ENTRIES LOGINSCREEN ***
# *** BUTTONS ***
loginButton = Button(root, text="Login")
loginButton.bind("<Button-1>", loginCredentials)
loginButton.grid(row=6,column=0, sticky=E)
# *** MAIN MENU ***
menu= Menu(root)
root.config(menu=menu)
subMenu = Menu(root)
menu.add_cascade(label="Menu", menu=subMenu)
subMenu.add_command(label="Preview", command=previewEmail)
root.mainloop()
writing to a global variable inside a function works like this:
a = None
def foo():
global a
a = 42
a = 3
foo()
print(a)
Output:
42
The root of the problem is that you're using local variables everywhere but expecting them to be global.
If you want a variable to be accessible outside of the scope it was created in, you must define it as global1
def setLoginCredentials():
global USERNAME
global PASSWORD
global entryLoginUsername
global entryLoginPassword
...
def loginCredentials(event):
global entryLoginUsername
global entryLoginPassword
...
1 Strictly speaking this isn't true - global variables can be read without being declared global, but they can't be modified. However, since your intent is to use global variables, declaring them as global even when you don't need to will clarity to your code.
For more information see What are the rules for local and global variables in Python? in the official python documentation.
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)
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:
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.