How to continue the program outside the function? - python

I'm new to python and got stuck while trying to build a GUI. I can't find a way to extract data from the 'login' function, which would be the new TopLevel window created after the user logs in. Because of that, I have to write the remaining code inside the 'login function', but I have the impression that there must be another way around. I tried making the new top level global, but it returns that the new variable is not defined.
from tkinter import *
from tkinter import messagebox
root = Tk()
login_frame = LabelFrame(root, text = "login info").pack()
user_field = Label(login_frame, text = "user: ")
user_field.grid(row = 0,column = 0)
pass_field = Label(login_frame, text = "pass: ")
pass_field.grid(row = 1, column = 0)
user_input = Entry(login_frame)
user_input.grid(row = 0, column = 1)
pass_input = Entry(login_frame, show = "*")
pass_input.grid(row = 1, column = 1)
def login():
if user_input.get() == "user" and pass_input.get() == "user":
if messagebox.showinfo("blah", "blah") == "ok":
pass_input.delete(0, END)
user_input.delete(0, END)
root.withdraw()
**app = Toplevel()**
else:
messagebox.showerror("blah", "blah")
pass_input.delete(0, END)
user_input.delete(0, END)
login_btn = Button(login_frame, text = "LOGIN")
login_btn.grid(row = 2, column = 0)
exit_btn = Button(login_frame, text = "SAIR")
exit_btn.grid(row = 2, column = 1)
root.mainloop()

Your code is breaking indentation. The lines following the definition of the function must be inside the scope of the function, like this:
def login():
if user_input.get() == "user" and pass_input.get() == "user":
if messagebox.showinfo("blah", "blah") == "ok":
...
Regardless of that, you may return any type of data at the end of a function. Consider exposing your TopLevel app like this:
return TopLevel()

Related

Label not changing in window - tkinter

I have this code that I'm following from a video. This is a function that gets activated when a button is pressed. In some parts I want to erase the previous output in a label every time the button is pressed:
# Search customers
def search_customers():
search_customers = Tk()
search_customers.title("Search Customers")
search_customers.geometry("1300x600")
searched_label = Label(search_customers)
searched_label.grid(row=2, column=0)
test = Label(search_customers)
test.grid(row=3, column=0)
def search_now():
# searched_label = Label(search_customers)
# searched_label.grid(row=2, column=0)
selected = drop.get() # This is a Combobox
if selected == 'Search By...':
sql = ""
test['text'] = 'You forgot to pick an option'
elif selected == 'Last Name':
sql = "SELECT * FROM customers WHERE last_name = %s"
elif selected == 'Email Address':
sql = "SELECT * FROM customers WHERE email = %s"
elif selected == 'Customer ID':
sql = "SELECT * FROM customers WHERE user_id = %s"
searched = search_box.get()
name = (searched, )
result = my_cursor.execute(sql, name)
if selected == "Search By...":
result = ''
else:
result = my_cursor.fetchall()
if not result:
result = "Record Not Found"
test['text'] = ''
searched_label['text'] = result
elif result:
test['text'] = ''
searched_label['text] = ''
searched_label = Label(search_customers)
for index, x in enumerate(result):
num = 0
index += 2
for y in x:
searched_label = Label(search_customers, text=y)
searched_label.grid(row=index, column=num)
num += 1
The thing is, every time the code reaches this statement: searched_label['text'] = '', it says: variable referenced before the assignment but that doesn't happen with test['text'] = '' even though both labels are created in the same scope.
The only way it worked was to create searched_label inside the search_now() (see the commented lines and let's pretend to uncomment them and comment the ones above).
With the lines uncommented inside search_now(), when it reaches this statement: if not result, it sets searched_label['text'] = result without a problem, but when it reaches the last elif, it doesn't set searched_label['text'] = '', actually, let's say the code was run and it first reached the if not result: statement so when the button is press again and it reaches the last elif it doesn't erase the previous output with searched_label['text] = ''.
In this last elif, I tried reached_label.grid_remove() and creating the label again but the previous output still remains so it mixes with the new output.
Thanks in advance, I'm still learning and I hope my question is clear enough
If you want to change the texts of Label widgets regularily, it pays to use the parameter textvariable. It takes a StringVar() object that can be changed by any function. As soon as the StringVar gets a new value, the label changes.
I do not see the whole of your program, but this is how it works in general:
def search_customers():
search_customers = Tk()
search_customers.title("Search Customers")
search_customers.geometry("1300x600")
global labeltext
labeltext = StringVar() ## Initiate a string variable
labeltext.set("This is the mutable text")
searched_label = Label(search_customers,textvariable=labeltext)
searched_label.grid(row=2, column=0)
test = Button(search_customers,text="Change it",command=change)
test.grid(row=3, column=0)
def change():
labeltext.set("This is a new text")
If the program gets more complicated, you might also consider defining the dialog box as a new class, iheriting from Frame. There, you can define methods that have access to all widgets and variables without the need of global variables.
I can't help you. Actually, need more information. I am using match case statements instead of if/else.
Code:
def search_now():
searched_label = Label(search_customers)
searched_label.grid(row=2, column=0)
selected = drop.get() # This is a Combobox
match selected:
case 'Search By...':
sql = ""
test['text'] = 'You forgot to pick an option'
case 'Last Name':
sql = "SELECT * FROM customers WHERE last_name = %s"
case 'Email Address':
sql = "SELECT * FROM customers WHERE email = %s"
case 'Customer ID':
sql = "SELECT * FROM customers WHERE user_id = %s"
searched = search_box.get()
name = (searched, )
result = my_cursor.execute(sql, name)
if selected == "Search By...":
result = ''
else:
result = my_cursor.fetchall()
if not result:
result = "Record Not Found"
#test['text'] = ''
searched_label.config{text=result)
elif result:
#test['text'] = ''
searched_label.config(text='')
#searched_label = Label(text=search_customers)
for index, x in enumerate(result):
num = 0
index += 2
for y in x:
#searched_label = Label(search_customers, text=y)
searched_label.config(text=y)
Let me know if this work.

Tkinter/Python hanging on user response if response is the last option in a while or if loop

The following code works for requesting input from a user through the Tkinter GUI and turning that input into a usable variable in the main script. However, any value that I put as the last in a list in the if statement (here "4") will hang and crash the program upon enter. This was also the case for "n" in a yes/no scenario. It also happens if I replace the if statement with a while not in [values] - the final value will crash the program. Is this just a quirk of Tkinter or is there something that I am missing?
import tkinter as tk
from tkinter import *
# get choice back from user
global result
badinput = True
while badinput == True:
boxwidth = 1
result = getinput(boxwidth).strip().lower()
if result in ['1', '2', '3', '4']:
badinput = False
# iterate through play options
if result == '1':
# Do Something
elif result =='2':
# Do Something
elif result =='3':
# Do Something
else:
# Do Something
def getinput(boxwidth):
# declaring string variable for storing user input
answer_var = tk.StringVar()
# defining a function that will
# get the answer and set it
def user_response(event):
answer_var.set(answer_entry.get())
return
answer_entry = tk.Entry(root, width = boxwidth, borderwidth = 5)
# making it so that enter calls function
answer_entry.bind('<Return>', user_response)
# placing the entry
answer_entry.pack()
answer_entry.focus()
answer_entry.wait_variable(answer_var)
answer_entry.destroy()
return answer_var.get()
In case anyone is following this question, I did end up solving my problem with a simple if statement within the callback. I can feed a dynamic "choicelist" of acceptable responses into the callback upon user return. If the answer is validated, the gate_var triggers the wait function and sends the program and user response back into the program.
'''
def getinput(boxwidth, choicelist):
# declaring string variable for storing user input
answer_var = tk.StringVar()
gate_var = tk.StringVar()
dumplist = []
# defining a function that will
# get the answer and set it
def user_response(event):
answer_var.set(answer_entry.get())
if choicelist == None:
clearscreen(dumplist)
gate_var.set(answer_entry.get())
return
if answer_var.get() in choicelist:
# passes a validated entry on to gate variable
clearscreen(dumplist)
gate_var.set(answer_entry.get())
else:
# return to entry function and waits if invalid entry
clearscreen(dumplist)
ErrorLabel = tk.Label(root, text = "That is not a valid response.")
ErrorLabel.pack()
ErrorLabel.config(font = ('verdana', 18), bg ='#BE9CCA')
dumplist.append(ErrorLabel)
return
global topentry
if topentry == True:
answer_entry = tk.Entry(top, width = boxwidth, borderwidth = 5)
else:
answer_entry = tk.Entry(root, width = boxwidth, borderwidth = 5)
# making it so that enter calls function
answer_entry.bind('<Return>', user_response)
# placing the entry
answer_entry.pack()
answer_entry.focus()
answer_entry.wait_variable(gate_var)
answer_entry.destroy()
return answer_var.get()
'''

How to get the string out of a box which a user has inputted into? Tkinter Python

Hello i am making a log in program on tkinter and i am having trouble when using the box widget where the user is able to input a string. i am trying to take that string out and store it in a variable ready for another time but the way i am trying to do it doesn't actually save anything, is there something that im doing wrong?
from tkinter import *
Wsignup = Tk()
Wsignup.title('Sign up')
UserLabel = Label(Wsignup, text = "Please enter your new username: ")
UserLabel.grid(row = 1, column = 1, sticky = E)
UserEntry = Entry(Wsignup)
UserEntry.grid(row = 1, column = 2, sticky = E)
Username = UserEntry.get()
PassLabel = Label(Wsignup, text = "Please enter your new password: ")
PassLabel.grid(row = 2, column = 1, sticky = E)
PassEntry = Entry(Wsignup, show = '*')
PassEntry.grid(row = 2, column = 2, sticky = E)
Password = PassEntry.get()
You are calling get() before the user had a chance to enter something. Add a Button and call get() in a callback function instead:
def callback():
# global Username, Password # if you want to set global variables
Username = UserEntry.get()
Password = PassEntry.get()
print(Username, Password) # or whatever you need to do with them
Button(Wsignup, text="Login", command=callback).grid(row=3,column=1)

Python 3 and Tkinter- how to control a quiz loop

I'm sure the answer to this is obvious but I cannot spot it! I have a very basic quiz(using Tkinter and Python 3) which uses 2 arrays , the question is displayed and then the answer entered is matched using the array index when the submit button is clicked.
The question at index 0 is displayed twice- cannot see why
The score does not increment correctly- even though it is a global variable- it just shows 1 each time.
How can I get the quiz to move to a print statement after the end of the list is reached?
I have tried putting an IF statement in the submit function to check the value of i but cannot get this to work. Can anyone point out my errors please?
from tkinter import *
global questions
questions =["What is the name of the Simpsons' next door neighbour?","What is the name of the school bus driver?",
"Who runs the Kwik-e-mart?","What does Bart do at the end of the opening credits?"]
global answers
answers = [ "Ned Flanders","Otto","Apu","Write On The Blackboard"]
global score
score = 0
global i
i = 0
def submit():
'''runs the submit button'''
global i
global score
question.config(text=questions[i])
if answer.get().lower()==answers[i].lower():
score+=1
else:
score=score
i+=1
scoretxt.config(text =str(score))
answer.delete(0,END)
window = Tk()
window.title("Simpsons Quiz")
window.wm_iconbitmap("homer.ico")
window.configure(background ="#ffd600")
banner = PhotoImage(file ="the-simpsons-banner.gif")
Label(window,image = banner).grid(row = 0,columnspan = 6)
Label(window,text = "Question : ",bg ="#ffd600",justify=LEFT).grid(row = 1,column = 0)
Label(window,text = "Type answer here: ",bg = "#ffd600",justify=LEFT).grid(row = 3, column = 0)
scoreLabel =Label(window,bg = "#ffd600")
scoretxt = Label(window,text ="Your score is: ?",bg = "#ffd600")
scoreLabel.grid(row=5,column = 2)
scoretxt.grid(row = 6,column = 2)
question=Label(window,bg = "white",text= questions[0],justify=LEFT)
question.grid(row =1,column=1)
answer = Entry(window,bg ="white",width = 30)
answer.grid(row = 3,column=1)
# make a submit button
Button(window,text= "Submit",bg = "white",command = submit).grid(row = 3,column = 2)
mainloop()
1) You are printing the question before you increment i. That's why you get twice.
2) It is always 1 becuase of your usage of global. In python you use global keyword in which scope you want to change your variable. Sadly, my english is not good enough to explain this. Please check out these answers.
3) You can use try-except block. I used it there because that is the exact line where you get the error. You can expand its range.
from tkinter import *
questions =["What is the name of the Simpsons' next door neighbour?","What is the name of the school bus driver?",
"Who runs the Kwik-e-mart?","What does Bart do at the end of the opening credits?"]
answers = [ "Ned Flanders","Otto","Apu","Write On The Blackboard"]
#removed globals from here
score = 0
i = 0
def submit():
'''runs the submit button'''
global i
global score
if answer.get().lower()==answers[i].lower():
score+=1
i+=1 #first increment, then show the question since you already show it at startup
try: #since you get the IndexError on this line, I used on here
question.config(text=questions[i])
except IndexError:
print ("something")
scoretxt.config(text = "Your score is: {}".format(str(score)))
answer.delete(0,END)
window = Tk()
window.title("Simpsons Quiz")
window.wm_iconbitmap("homer.ico")
window.configure(background ="#ffd600")
banner = PhotoImage(file ="the-simpsons-banner.gif")
Label(window,image = banner).grid(row = 0,columnspan = 6)
Label(window,text = "Question : ",bg ="#ffd600",justify=LEFT).grid(row = 1,column = 0)
Label(window,text = "Type answer here: ",bg = "#ffd600",justify=LEFT).grid(row = 3, column = 0)
scoreLabel =Label(window,bg = "#ffd600")
scoretxt = Label(window,text ="Your score is: ?",bg = "#ffd600")
scoreLabel.grid(row=5,column = 2)
scoretxt.grid(row = 6,column = 2)
question=Label(window,bg = "white",text= questions[0],justify=LEFT)
question.grid(row =1,column=1)
answer = Entry(window,bg ="white",width = 30)
answer.grid(row = 3,column=1)
# make a submit button
Button(window,text= "Submit",bg = "white",command = submit).grid(row = 3,column = 2)
mainloop()
Also you might want to use a dictionary instead of questions-answers lists.

Bug in message sending program

I am just experimenting on a messaging program which runs on one computer only. Okay, here's the problem: If I login as an user and send a message to another user, even when I login to the message receiving user, no messages are not there(it say no messages). Please help me out. You are also welcome to give your own suggestions and ways to simplify the code.
import Tkinter as tk
import sys
import tkMessageBox
import csv
accounts = dict()
messages = []
messagerec = []
messagesen = []
csvpath = "C:/Users/user1/Desktop/abc.csv"
csvreader = csv.reader(open(csvpath))
for y, z in csvreader:
accounts[y] = z
def GetUser():
user = userid.get()
return user
def GetPass():
password = passid.get()
return password
def SignUp():
def signupgo():
newuser = newuserid.get()
newpass = newpassid.get()
if newuser in accounts:
tkMessageBox.showerror("Username Taken", 'Sorry! The username you have requested has already been taken. Please try another username.' [2])
else:
accounts[newuser] = newpass
tkMessageBox.showinfo("Account Created", 'Congratulations! Your account has been created' [2])
newuserid = tk.StringVar()
newpassid = tk.StringVar()
SignUpWin = tk.Tk()
NewUserLabel = tk.Label(SignUpWin, text="New Username: ").pack()
NewUserInput = tk.Entry(SignUpWin,textvariable=newuserid).pack()
NewPassLabel = tk.Label(SignUpWin, text="New Password: ").pack()
NewPassInput = tk.Entry(SignUpWin, textvariable=newpassid).pack()
CreateAccount = tk.Button(SignUpWin, text="Create Account", command=signupgo).pack()
def logingo():
user = GetUser()
password = GetPass()
if user in accounts:
if accounts[user] == password:
LoggedIn(user)
elif accounts[user] != password:
tkMessageBox.showerror("Wrong Password", 'Try Again! You have entered the wrong password.')
elif user not in accounts:
tkMessageBox.showerror("User not existing", 'Try Again or Create an account! The username you have provided is not existing.')
def LoggedIn(user):
def MessageButtonClick():
if tkMessageBox.askquestion('Compose or Inbox?', 'Do you want to access your inbox(Yes) or compose a new message(No)?') == 'yes':
OpenInbox(user)
else:
MessageSender(user)
The message sending part starts here.
def MessageSender(user):
messagerecvar = tk.StringVar()
messagecontentvar = tk.StringVar()
messagesenderwin = tk.Tk()
messagereclabel = tk.Label(messagesenderwin, text="Receiver:").pack()
messagerecinput = tk.Entry(messagesenderwin, textvariable=messagerecvar).pack()
messagecontentlabel = tk.Label(messagesenderwin, text="Content:").pack()
messagecontentinput = tk.Entry(messagesenderwin, textvariable=messagecontentvar).pack()
messagecontent = messagecontentvar.get()
messagerec = messagerecvar.get()
messagesendgobutton = tk.Button(messagesenderwin, text='Send Message', command=lambda:sendmessagego(messagecontent, user, messagerec)).pack()
def sendmessagego(content, sender, receiver):
messages.append(content)
messageno = len(messages)
messagerec.append(receiver)
messagesen.append(sender)
tkMessageBox.showinfo("Message Sent", 'Your message has been sent.')
def OpenInbox(user):
if 'a' in messagerec:
lenmess = messagerec.index(user)
tkMessageBox.showinfo('Message from '+messagesen[lenmess], 'Message from '+messagesen[lenmess]+': '+messages[lenmess])
elif user not in messagerec:
tkMessageBox.showinfo('No Messages', 'Sorry, no messages were found')
loggedinwin = tk.Tk()
tkMessageBox.showinfo("Welcome", 'Hello, '+user)
HomeLabel = tk.Label(loggedinwin, text="Home").pack()
MessageMenuButton = tk.Button(loggedinwin, text="Messaging", command=MessageButtonClick).pack()
maingui = tk.Tk()
userid = tk.StringVar()
passid = tk.StringVar()
UserEnterLabel = tk.Label(maingui, text="Username: ").pack()
UserInput = tk.Entry(maingui, textvariable=userid).pack()
PassEnterLabel = tk.Label(maingui, text="Password: ").pack()
PassInput = tk.Entry(maingui, textvariable=passid).pack()
LoginGo = tk.Button(maingui, text="Login", command=logingo).pack()
SignUpGo = tk.Button(maingui, text="Sign Up", command=SignUp).pack()
maingui.mainloop()
The first problem is that you're creating more than one instance of Tk. Tkinter isn't designed to work that way, and will yield unexpected results. If you need more than one window you need to create instances of Toplevel

Categories