I am creating a program with tkinter which comes with a default name and password stored in a text file. After login you need to open the Toplevel window and type in the name and password you want to use in your subsequent logins. I have defined my variables but if I want to overwrite the text file I receive the below:
Error "NameError: name 'e1' is not defined"
Which I know I have defined.
import sys
from tkinter import messagebox
from tkinter import *
now = open("pass.txt","w+")
now.write("user\n")
now.write("python3")
now.close()
def login_in():
with open("pass.txt") as f:
new = f.readlines()
name = new[0].rstrip()
password = new[1].rstrip()
if entry1.get() == name and entry2.get() == password:
root.deiconify()
log.destroy()
else:
messagebox.showerror("error","login Failed")
def change_login():
ch = Toplevel(root)
ch.geometry('300x300')
e1 = Entry(ch, width=20).pack()
e2 = Entry(ch, width=20).pack()
sb = Button(ch, text="save", command=save_changes).pack()
def save_changes(): # function to change data in the txt file
data = e1.get() + "\n " + e2.get()
with open("pass.txt", "w") as f:
f.writelines(data)
root= Tk()
log = Toplevel()
root.geometry("350x350")
log.geometry("200x200")
entry1 = Entry(log)
entry2 = Entry(log)
button1 = Button(log, text="Login", command=login_in) #Login button
entry1.pack()
entry2.pack()
button1.pack()
label = Label(root, text="welcome").pack()
butt = Button(root, text="change data in file", command=change_login).pack()
root.withdraw()
root.mainloop()
So you have a few options here but in general you have 2 major issues.
The first issue is the use of .pack() after the creation of your e1 and e2 entry fields. This is a problem for the get() method as the geometry manager will return None if you pack this way. The correct method is to create the widget first with e1 = Entry(ch, width=20) and then pack it on the next line with e1.pack() this will allow get() to work on e1.
The second issue is the matter of local variables vs global variables. You have created e1 and e2 inside of the function change_login() and without telling python that e1 and e2 are global variables it will automatically assume you want them as local variables. This means the variables are only accessible from within the function they are created in.
You have a few options and I will break them out for you.
1) The quick and dirty option is to assign e1 and e2 as global variables. This can be done by using global var_name, var2_name, and_so_on so in this case add this line to the top of your change_login(): and save_changes() functions:
global e1, e2
This well tell python to add e1 and e2 to the global name space and it will allow save_changes() to work with the variables in the global name space.
2) Another method is to pass the 2 variables to save_changes() using the button command. We will need to use lambda for this and we can accomplish this by adding:
command = lambda e1=e1, e2=e2: save_changes(e1, e2)
to the button created in change_login() and adding the 2 arguments to save_changes() like this:
save_changes(e1, e2)
This will work just as well as the first option and it also avoids the use of global variables.
3) A third option is to create the entire program as a class and to use class attributes to allow the variables to work with all methods within the class.
Below is an example of your code using the 1st option:
import sys
from tkinter import messagebox
from tkinter import *
now = open("pass.txt","w+")
now.write("user\n")
now.write("python3")
now.close()
def login_in():
with open("pass.txt") as f:
new = f.readlines()
name = new[0].rstrip()
password = new[1].rstrip()
if entry1.get() == name and entry2.get() == password:
root.deiconify()
log.destroy()
else:
messagebox.showerror("error","login Failed")
def change_login():
global e1, e2
ch = Toplevel(root)
ch.geometry('300x300')
e1 = Entry(ch, width=20)
e1.pack()
e2 = Entry(ch, width=20)
e2.pack()
sb = Button(ch, text="save", command=save_changes).pack()
def save_changes(): # function to change data in the txt file
global e1, e2
data = e1.get() + "\n" + e2.get() # removed space after \n
with open("pass.txt", "w") as f:
f.writelines(data)
root= Tk()
log = Toplevel()
root.geometry("350x350")
log.geometry("200x200")
entry1 = Entry(log)
entry2 = Entry(log)
button1 = Button(log, text="Login", command=login_in) #Login button
entry1.pack()
entry2.pack()
button1.pack()
label = Label(root, text="welcome").pack()
butt = Button(root, text="change data in file", command=change_login).pack()
root.withdraw()
root.mainloop()
Below is an example of your code using the 2nd option:
import sys
from tkinter import messagebox
from tkinter import *
now = open("pass.txt","w+")
now.write("user\n")
now.write("python3")
now.close()
def login_in():
with open("pass.txt") as f:
new = f.readlines()
name = new[0].rstrip()
password = new[1].rstrip()
if entry1.get() == name and entry2.get() == password:
root.deiconify()
log.destroy()
else:
messagebox.showerror("error","login Failed")
def change_login():
ch = Toplevel(root)
ch.geometry('300x300')
e1 = Entry(ch, width=20)
e1.pack()
e2 = Entry(ch, width=20)
e2.pack()
Button(ch, text="save", command=lambda e1=e1, e2=e2: save_changes(e1, e2)).pack()
def save_changes(e1, e2): # function to change data in the txt file
data = e1.get() + "\n" + e2.get() # removed space after \n
with open("pass.txt", "w") as f:
f.writelines(data)
root= Tk()
log = Toplevel()
root.geometry("350x350")
log.geometry("200x200")
entry1 = Entry(log)
entry2 = Entry(log)
button1 = Button(log, text="Login", command=login_in) #Login button
entry1.pack()
entry2.pack()
button1.pack()
label = Label(root, text="welcome").pack()
butt = Button(root, text="change data in file", command=change_login).pack()
root.withdraw()
root.mainloop()
Below is an example of your code converted to a class and using class attributes to avoid the use of global variables.
import sys
from tkinter import messagebox
from tkinter import *
class MyApp(Frame):
def __init__(self, master, *args, **kwargs):
Frame.__init__(self, master, *args, **kwargs)
self.master = master
self.master.withdraw()
self.log = Toplevel()
self.master.geometry("350x350")
self.log.geometry("200x200")
self.entry1 = Entry(self.log)
self.entry2 = Entry(self.log)
self.button1 = Button(self.log, text="Login", command=self.login_in)
self.entry1.pack()
self.entry2.pack()
self.button1.pack()
Label(root, text="welcome").pack()
Button(root, text="change data in file", command=self.change_login).pack()
def login_in(self):
with open("pass.txt") as f:
new = f.readlines()
name = new[0].rstrip()
password = new[1].rstrip()
if self.entry1.get() == name and self.entry2.get() == password:
self.master.deiconify()
self.log.destroy()
else:
messagebox.showerror("error","login Failed")
def change_login(self):
ch = Toplevel(self.master)
ch.geometry('300x300')
self.e1 = Entry(ch, width=20)
self.e1.pack()
self.e2 = Entry(ch, width=20)
self.e2.pack()
Button(ch, text="save", command=self.save_changes).pack()
def save_changes(self):
data = "{}\n{}".format(self.e1.get(), self.e2.get())
with open("pass.txt", "w") as f:
f.writelines(data)
if __name__ == "__main__":
now = open("pass.txt","w+")
now.write("user\n")
now.write("python3")
now.close()
root = Tk()
app = MyApp(root)
root.mainloop()
Related
I cannot get my code to pass the pop up text entry to a global variable i am also attempting to set this global variable as the default text in the entry field in all future instances.
Pop up -> Enter Filepath -> accept&close -> Re-open shows last filepath present as default -> if changed new filepath entry becomes default in future.
import tkinter as tk
from tkinter import ttk
from tkinter import *
master = tk.Tk()
Var1 = StringVar()
Filepath_Var = None
def A_Connect():
root = Tk()
root.title("Entry Field")
def entry_field():
global Filepath_Var
Filepath_Var = Var1.get()
tk.Label(root, text="filepath: ").grid(row=0)
e1 = tk.Entry(root, textvariable=Var1)
tk.Label(root, text="Item Number: ").grid(row=1)
e2 = tk.Entry(root)
#e1.insert(0, r"C:\Users\zxy\ghj\iugf\Bea\something.xlsx")
e1.insert(0, Var1.get())
e1.grid(row=0, column=1)
e2.grid(row=1, column=1)
Button(root, text = 'Accept', command = entry_field).grid(row=3, column=1,
sticky=W, pady=4)
root.mainloop()
note = ttk.Notebook(master)
tab1 = tk.Frame(note)
canvas7 = Canvas(tab1, width=520, height=350)
canvas7.pack()
A_Button = tk.Button(tab1, text="A",
width=12, height=3,command=A_Connect, anchor = 'w')
A_Button_Window = canvas7.create_window(20, 120, anchor = 'sw',
window = A_Button)
note.add(tab1, text = " Main ")
note.pack()
master.mainloop()
As a follow up to your earlier question, I encapsulated an example of the (bare bones) desired behavior in two classes:
The main App consists of a button that launches an entry popup; upon filling the fields and accepting, the value in the entry is provided to the App, and the popup closed.
The value entered is stored by the App, and used to populate the entry field of the entry fields in successive popups.
You will probably want to add confirmations and verifications before changing the defaults, and closing the popup, but here, you have the basic skeleton to attach this to.
import tkinter as tk
class PopUpEntry(tk.Toplevel):
def __init__(self, master, default_value=None):
self.master = master
super().__init__(self.master)
if default_value is None:
self.default_entry = 'C:*****\somthing.xlsx'
else:
self.default_entry = default_value
self.title("Entry Field")
tk.Label(self, text="Filepath: ").pack()
self.e1 = tk.Entry(self)
self.e1.insert(0, self.default_entry)
self.e1.pack()
tk.Button(self, text = 'Accept', command=self.entry_field).pack()
def entry_field(self):
self.default_entry = self.e1.get()
self.master.provide_entry_value(self.default_entry)
self.destroy()
class App(tk.Tk):
def __init__(self):
super().__init__()
self.pop_entry = tk.Button(self, text='launch entry', command=self.launch_entry)
self.pop_entry.pack()
self.default_entry_value = None
self.mainloop()
def launch_entry(self):
PopUpEntry(self, self.default_entry_value)
def provide_entry_value(self, value):
self.default_entry_value = value
print(self.default_entry_value)
App()
Why it does not print the string values I have entered into the textbox in the newwindow?
from tkinter import *
def newwindow():
newwindow = Tk()
newwindow.title('Sign Up')
newwindow.geometry('200x400')
def sign_done():
david = a.get()
javed = b.get()
lbee = Label(newwindow, text=david).pack()
baeee = Label(newwindow, text=javed).pack()
a = StringVar()
b = StringVar()
user = Entry(newwindow, textvariable=a).pack()
pword = Entry(newwindow, textvariable=b).pack()
done = Button(newwindow, text='done now', command=sign_done).pack()
newwindow.mainloop()
root = Tk()
root.title('Gulmeena')
root.geometry("500x200")
button = Button(root, text='Go', command=newwindow).pack()
root.mainloop()
Please do not use Classes
Use Tk only to create main window. To create any other window use Toplevel. And use only one mainwindow().
var = Widget(...).pack() assigns None to var because pack()/grid()/place() returns None. You have to do it in two lines.
var = Widget(...)
var.pack().
If you don't need var then you can do
Widget(...).pack()
To make code more readable
I use import tkinter as tk to show I use tk.Button, not ttk.Button nor my own classButton`
I use name user_var and password_var which means something
I put all functions at the beginning - even inside newwindow
Code:
import tkinter as tk
def newwindow():
def sign_done():
david = user_var.get()
javed = password_var.get()
tk.Label(newwindow, text=david).pack()
tk.Label(newwindow, text=javed).pack()
newwindow = tk.Toplevel()
newwindow.title('Sign Up')
newwindow.geometry('200x400')
user_var = tk.StringVar()
password_var = tk.StringVar()
user = tk.Entry(newwindow, textvariable=user_var)
user.pack()
pword = tk.Entry(newwindow, textvariable=password_var)
pword.pack()
tk.Button(newwindow, text='done now', command=sign_done).pack()
root = tk.Tk()
root.title('Gulmeena')
root.geometry("500x200")
tk.Button(root, text='Go', command=newwindow).pack()
root.mainloop()
You can do the same without StringVars
import tkinter as tk
def newwindow():
def sign_done():
david = user.get()
javed = pword.get()
tk.Label(newwindow, text=david).pack()
tk.Label(newwindow, text=javed).pack()
newwindow = tk.Toplevel()
newwindow.title('Sign Up')
newwindow.geometry('200x400')
user = tk.Entry(newwindow)
user.pack()
pword = tk.Entry(newwindow)
pword.pack()
tk.Button(newwindow, text='done now', command=sign_done).pack()
root = tk.Tk()
root.title('Gulmeena')
root.geometry("500x200")
tk.Button(root, text='Go', command=newwindow).pack()
root.mainloop()
from Tkinter import *
root = Tk()
root.geometry("230x100")
L1 = Label(root, text="Login page", bg = "blue", fg = "white")
L1.pack(fill = X, ipadx = 5, ipady = 5)
V = StringVar(root, value='Enter username here')
E1 = Entry(root, textvariable=V)
E1.pack(side = LEFT, padx = 5, pady = 5)
def Login():
username = V.get()
print "Username is '" + username + "'"
B1 = Button(root, text ="Login" , command = Login)
B1.pack(side = RIGHT, fill = X, pady=5)
mainloop()
I have been trying to get the value of 'username' in the function Login() to use it on another python program.
I have tried setting it as global variable and changing its scope but I am not getting anything.
I need to use the value of 'Username' outside the function Login(). Please provide your insights.
Think about scope for a moment. When your program ends, all memory (meaning variables, objects, etc.) are released. The only 2 ways I can think of to pass something from one program to another is:
1) Write the username value to a file which the next program can read as part of its startup.
2) Have a third "controller" or "launcher" program that runs the program above, takes a return value from that program, then passes that value as a parameter to the next program.
But in any case, you will have to save that value past the scope of the program above.
1) Create a python file say 'global_vars.py' and add this line in it.
#global_vars.py
global_V = ''
2) Import this global_vars.py wherever you want set the variable as below:
#main.py
from Tkinter import *
import global_vars
root = Tk()
root.geometry("230x100")
L1 = Label(root, text="Login page", bg = "blue", fg = "white")
L1.pack(fill = X, ipadx = 5, ipady = 5)
V = StringVar(root, value='Enter username here')
#Set the global variable
global_vars.global_V = V
E1 = Entry(root, textvariable=V)
E1.pack(side = LEFT, padx = 5, pady = 5)
3) Consider you want to use this value in python program present in file "test.py". Just import global_vars.py and use this variable
#test.py
import global_vars.py
def printUserName():
print "Username is -", global_vars.global_V
If you have to python files, one called main.py that contains your main program (I assumed it was a GUI program) and the login.py file that contains the login program.
main.py
from tkinter import Tk, Label
from login import LoginGUI
class mainGUI(Tk):
def __init__(self):
Tk.__init__(self)
Label(self, text="You need to login first",
bg="blue", fg="white").pack(fill="x", ipadx=5, ipady=5)
# open login dialog
login = LoginGUI(self)
# wait for the user to log in
self.wait_window(login)
username = login.getLogin()
Label(self,
text="Your username is " + username).pack(fill="x", ipadx=5, ipady=5)
self.mainloop()
if __name__ == '__main__':
mainGUI()
login.py
from tkinter import Toplevel, StringVar, Entry, Button, Label
from tkinter import Toplevel, StringVar, Entry, Button, Label
class LoginGUI(Toplevel):
def __init__(self, master):
Toplevel.__init__(self, master)
self.transient(master)
self.geometry("230x100")
Label(self, text="Login page",
bg="blue", fg="white").pack(fill="x", ipadx=5, ipady=5)
self.username = ""
self.usernameVar = StringVar(self, value='Enter username here')
E1 = Entry(self,
textvariable=self.usernameVar)
E1.pack(side="left", padx=5, pady=5)
Button(self, text="Login",
command=self.Login).pack(side="right", fill="x", pady=5)
E1.focus_set()
def Login(self):
self.username = self.usernameVar.get()
self.destroy()
def getLogin(self):
return self.username
If your main program have no GUI, replace Toplevel by Tk in login.py and add a self.mainloop at the end of the __init__ method.
You can launch the other program using subprocess, or refactor the other program so the username can be passed as the parameter of a function, and import that program as module of your main program.
What I need is to make the view orders button to get the text from the Customer.txt file and set it inside a textfield i made.
#make order,cancel,view
from tkinter import *
import tkinter.messagebox
root = Tk()
file = open("Customer.txt", "w")
def textW():
outFile = open("Customer.txt", "wt")
def CancelOrder():
outFile=open("Customer.txt", "w")
outFile.write("")
tkinter.messagebox.showinfo("Cancel Order", "Your order has been canceled")
def ViewOrder():
outFile = open('Customer.txt', 'r')
test = outFile.read()
#tViewOrder.set(test)
print (test)
#test.set(tViewOrder)
#outFile.close()
def MakeOrder():
outFile=open("Customer.txt", "w")
outFile.write("" + tMakeOrder.get())
tkinter.messagebox.showinfo("Make Order", "Order has been placed. Thank you!")
#Labels
lMakeOrder = Label(root, text="Make an order")
lViewOrder = Label(root, text="View Order")
#TextFields
tMakeOrder = Entry(root)
tViewOrder = Entry(root, state="disabled")
#Buttons
bMakeOrder = Button(root, text="Make order",bg="black",fg="green", command=MakeOrder)
bCancelOrder = Button(root, text="Cancel order",bg="black",fg="green", command=CancelOrder)
bViewOrder = Button(root, text="View orders",bg="black",fg="green", command=ViewOrder)
#Position
lMakeOrder.grid(row=0)
lViewOrder.grid(row=1)
tMakeOrder.grid(row=0, column=2)
tViewOrder.grid(row=1, column=2)
bMakeOrder.grid(row=4)
bViewOrder.grid(row=4, column=2)
bCancelOrder.grid(row=4, column=4)
#Window stuff
root.title("Sky is a shit name service - Customer")
root.geometry("300x300")
root.mainloop()
You can put text inside your Entry by calling insert function on it.
MyEntry.insert(POSITION, TEXT)
Oh and one more thing. You can't insert anything in the entry if it's disabled.
So here is your modified function:
def ViewOrder():
outFile = open('Customer.txt', 'r')
test = outFile.read()
tViewOrder['state'] = 'normal'
tViewOrder.delete(0, 'end') #Remove everything before
tViewOrder.insert(0, test)
tViewOrder['state'] = 'disabled'
outFile.close()
from tkinter import *
rGui = Tk()
rGui.title("Recipe's")
rGui.geometry("400x300")
rGui.resizable(0,0)
rNameLabel = Label(rGui, text="What is your Recipe called?").grid(row=1, column=1)
rEnt = Entry(rGui)
rEnt.grid(row=1, column=2)
def RecipeName():
f = open(rEnt.get()+'.txt','a')
f.write("Recipe name: "+str(rEnt.get())+"\n")
f.close()
rConButton = Button(rGui, text="Confirm", command=RecipeName).grid(row=1, column=3)
Hello, this code here opens a GUI with buttons. Now once the user has input their recipe name I'd like it to clear the screen so I can add more buttons. Now I’m not sure how to get the grid_forget working so if someone could edit the code so it forgets it so I can look at it for next time I'd appreciate it.
This is one example of how you can make pages in your program using the grid geometry manager:
import tkinter
class Application(tkinter.Frame):
#classmethod
def main(cls):
tkinter.NoDefaultRoot()
root = tkinter.Tk()
root.title('Recipes')
root.geometry('400x300')
root.resizable(False, False)
app = cls(root)
app.grid()
root.mainloop()
def __init__(self, master):
super().__init__(master)
self.create_first_screen()
self.first_screen.grid_remove()
self.create_second_screen()
self.second_screen.grid_remove()
self.first_screen.grid()
def create_first_screen(self):
self.first_screen = s1 = tkinter.Frame(self)
self.first_screen.grid(row=0, column=0)
# Create widgets.
s1.name_label = tkinter.Label(s1, text='What is your recipe called?')
s1.name_entry = tkinter.Entry(s1)
s1.con_button = tkinter.Button(s1, text='Confirm',
command=self.name_recipe)
# Grid each widget.
s1.name_label.grid(row=0, column=0)
s1.name_entry.grid(row=0, column=1)
s1.con_button.grid(row=0, column=2)
def create_second_screen(self):
self.second_screen = s2 = tkinter.Frame(self)
self.second_screen.grid(row=0, column=0)
# Create widgets.
s2.name_label = tkinter.Label(s2, text='What is your name?')
s2.name_entry = tkinter.Entry(s2)
s2.con_button = tkinter.Button(s2, text='Confirm',
command=self.name_yourself)
# Grid each widget.
s2.name_label.grid(row=0, column=0)
s2.name_entry.grid(row=0, column=1)
s2.con_button.grid(row=0, column=2)
def name_recipe(self):
name = self.first_screen.name_entry.get()
with open(name + '.txt', 'w') as file:
print('Recipe name:', name, file=file)
self.first_screen.grid_remove()
self.second_screen.grid()
def name_yourself(self):
name = self.second_screen.name_entry.get()
with open(name + '.txt', 'w') as file:
print('Your name:', name, file=file)
self.second_screen.grid_remove()
self.first_screen.grid()
if __name__ == '__main__':
Application.main()