Python Tkinter error: "Label has no __call__method" - python

Im trying to create a Python tkinter login registeration but running into a small issue.
The error message is:
self.Label_Name = Label(top, text="What is your username: ")
AttributeError: Label instance has no __call__ method
Please can you proof read my code:
from Tkinter import *
class Register:
def __init__(self, parent):
top = self.top = Toplevel(parent)
# Variables to store the entries
self.VarEntUser = StringVar()
self.VarEntPass = StringVar()
self.VarEntRetype = StringVar()
self.Label_Name = Label(top, text="What is your username: ")
self.Label_Password = Label(top, text="Enter a password: ")
self.Label_Retype = Label(top, text="Retype Password: ")
# Entry fields for the user to enter there details
self.Ent_Name = Entry(top, textvariable=self.VarEntUser)
self.Ent_Password = Entry(top, textvariable=self.VarEntPass)
self.Ent_Retype = Entry(top, textvariable=self.VarEntRetype)
# Puts all the fields ^, into the window
self.Label_Name.grid(row=0, sticky=W)
self.Label_Password.grid(row=1, sticky=W)
self.Label_Retype.grid(row=2, sticky=W)
self.Ent_Password.grid(row=1, column=1)
self.Ent_Retype.grid(row=2, column=1)
self.Ent_Name.grid(row=0, column=2)
# Run the RegisterCheck function
# submit button which Checks the Entered details then writes the user and pass to a .txt file
self.MySubmitButton = Button(top, text='Submit', command=RegisterCheck)
self.MySubmitButton.pack()
self.U = raw_input(self.VarEntUser.get())
self.P = raw_input(self.VarEntPass.get())
self.R = raw_input(self.VarEntRetype.get())
class LogIn:
def __init__(self, parent):
top = self.top = Toplevel(parent)
self.a = StringVar()
self.b = StringVar()
self.Label_Log_User1 = Label(top, text='Username:')
self.Label_Log_Pass = Label(top, text='Password: ')
self.Ent_User_Log = Entry(top, textvariable=self.a)
self.Ent_Pass_Log = Entry(top, textvariable=self.b)
self.Label_Log_User1.grid(row=1)
self.Pass_Log.grid(row=2)
self.EntUserLog.grid(row=1, column=1)
self.EntPassLog.grid(row=2, column=1)
self.User = raw_input(self.EntUserLog.get())
self.Pass = raw_input(self.EntUserLog.get())
# runs the 'LoginCheck' function
self.LogInButton = Button(top, text="Log In", command=LogInCheck)
self.LogInButton.pack()
def LogInCheck(self):
# Checks if the fields are blanking displaying an error
if len(self.User) <= 0 and len(self.Pass) <= 0:
print "Please fill in all fields."
else:
pass
# Checks to see if the user and pass have been created
if self.User in 'username.txt' and self.Pass in 'password':
print 'You are now logged in!'
else:
print "Log in Failed"
def RegisterCheck(self):
# Checks if the fields are blank
if len(self.P) <= 0 and len(self.U) <= 0:
print "Please fill out all fields."
else:
pass
# Check is the password and the retype match
if self.P == self.R:
pass
else:
print "Passwords do not match"
# After registering write the user and pass to a .txt file
with open('username.txt', 'a') as fout:
fout.write(self.U + '\n')
with open('password.txt', 'a') as fout:
fout.write(self.P + '\n')
# Depending on what the user chooses, either log in or register than opens the specific window
def launch_Register():
inputDialog = Register(root)
root.wait_window(inputDialog.top)
def launch_LogIn():
inputdialog2 = LogIn(root)
root.wait_window(inputdialog2.top)
root = Tk()
label = Label(root, text='Choose an option')
label.pack()
loginB = Button(root, text='Log In', command=launch_LogIn)
loginB.pack()
registerB = Button(root, text='Register', command=launch_Register)
registerB.pack()
root.mainloop()

The problem is that in this line
Label = Label(root, text='Choose an option')
you define a Label called Label, thus shadowing the Label constructor. Then, then you create the several labels in your Register and Login classes (triggered by those two buttons), the name Label is no longer bound to the constructor, but to that specific label.
Change the name of the label, then it should work. Also, I would advise you to use lower-case names for variables and methods. This alone might help prevent many such errors.
root = Tk()
label = Label(root, text='Choose an option')
label.pack()
loginB = Button(root, text='Log In', command=launch_LogIn)
loginB.pack()
registerB = Button(root, text='Register', command=launch_Register)
registerB.pack()
root.mainloop()
Note that there are a few many more problems with your code:
StringVar a and b should probably be self.a and self.b
You are trying to use raw_input to get the user input in the Entry widgets; this is wrong! Instead, just read the value of the variables to get the values, e.g. instead of self.User, use self.a.get()
do not mix grid and pack layout
if self.User in 'username.txt' will not check whether that name is in that file
loginCheck and registerCheck should be methods of the respective class
Once I'm at it, here's (part of) my version of your code, to help you getting started:
class Register:
def __init__(self, parent):
top = self.top = Toplevel(parent)
self.var_user = StringVar()
self.var_pass = StringVar()
self.var_retype = StringVar()
Label(top, text="What is your username: ").grid(row=0, sticky=W)
Label(top, text="Enter a password: ").grid(row=1, sticky=W)
Label(top, text="Retype Password: ").grid(row=2, sticky=W)
Entry(top, textvariable=self.var_user).grid(row=0, column=1)
Entry(top, textvariable=self.var_pass).grid(row=1, column=1)
Entry(top, textvariable=self.var_retype).grid(row=2, column=1)
Button(top, text='Submit', command=self.registerCheck).grid(row=3)
def registerCheck(self):
u, p, r = self.var_user.get(), self.var_pass.get(), self.var_retype.get()
if p and u:
if p == r:
logins[u] = p
else:
print "Passwords do not match"
else:
print "Please fill out all fields."
class LogIn:
# analogeous to Register; try to figure this out xourself
def launch_Register():
inputDialog = Register(root)
root.wait_window(inputDialog.top)
def launch_LogIn():
inputDialog = LogIn(root)
root.wait_window(inputDialog.top)
logins = {}
root = Tk()
Label(root, text='Choose an option').pack()
Button(root, text='Log In', command=launch_LogIn).pack()
Button(root, text='Register', command=launch_Register).pack()
root.mainloop()
Note that I changed the login "database" from files to a dictionary to keep things simple and to focus on the Tkinter problems. Of course, neither a simple dictionary nor a plain-text file is an appropriate way to store login information.
Also, I put the creation and the layout of the GUI widgets on one line. In this case this is possible since we do not need a reference to those widgets, but beware never to do e.g. self.label = Label(...).grid(...), as this will bind self.label to the result of grid, and not to the actual Label.
Finally, this will still print all the messages to the standard output. Instead, you should add another Label for that, or open a message dialogue, but this is left as an excercise to the reader...

Related

How to take information that takes entered into a entry box and save(dump) it in a text file(json)

I created a program which should dump the username and password in json file
But i am having problem in solving it
plz help
def createAccount():
A = tk.StringVar()
B = tk.StringVar()
root1 = Tk()
root1.resizable(0, 0)
root1.title('Signup')
instruction = Label(root1, text='Please Enter new Credentials')
instruction.grid(row=0, column=0, sticky=E)
nameL = Label(root1, text='New Username: ')
pwordL = Label(root1, text='New Password: ')
nameL.grid(row=1, column=0, sticky=W)
pwordL.grid(row=2, column=0, sticky=W)
nameE = Entry(root1, textvariable=A)
pwordE = Entry(root1, textvariable=B )
nameE.grid(row=1, column=1)
pwordE.grid(row=2, column=1)
signupButton = Button(root1, text='Signup')
signupButton.grid(columnspan=2, sticky=W)
root1.mainloop()
username = A
password = B
with open('user_accounts.json', 'r+') as user_accounts:
users = json.load(user_accounts)
if username in users.keys():
print('error')
else:
users[username] = [password, "PLAYER"]
user_accounts.seek(0)
json.dump(users, user_accounts)
user_accounts.truncate()
print("success")
I tried to convert username and password into string by using tk.StringVar()
But a error is displayed
Plz provide any appropriate solution
tkinter labels don't use normal Python variables types. Instead, they use tcl types, such as StringVar. to get the values of such variables, you can call their .get() method, which returns a native Python value. Now you can convert, change and use it as you like :)

Tkinter error local variable referenced before assignment

I am trying to make a program that once the tick box is ticked it then the fields for the email appear but when it is un-ticked then the fields disappear when you press Update.
but I keep on getting:
emailLabel.destroy()
UnboundLocalError: local variable 'emailLabel' referenced before assignment
Any suggestions?, here is my code below:
#so when you tick the box, the value is 1 so this checks for that and sets a equal to 1
#if the box isnt ticked then it checks a and if it is equal to 1 then it
#deletes the fields for the email and code.
#PLEASE HELP. Error is in this bit
def update(var1):
global signupas
global a
print(a)
checklist = var1.get()
print(checklist)
if checklist == 1:
a= 1
if a == checklist:
# // but it's referenced here:
global email
emailLabel = Label(signupas, text="Email")
emailLabel.grid(row=3, column=0)
email = StringVar()
emailEntry = Entry(signupas, textvariable=email)
emailEntry.grid(row=3, column=1)
codeLabel = Label(signupas, text="code")
codeLabel.grid(row=4, column=0)
code = StringVar()
codeEntry = Entry(signupas, textvariable=email)
codeEntry.grid(row=4, column=1)
#its on about this bit:
if a == 1 and checklist == 0:
emailLabel.destroy()
codeLabel.destroy()
signupas.mainloop()
#//this gets the information for the update as it checks for the check box
#//error isn't here but above so don't worry about signup().
def signup():
global signupas
signupas = tk.Toplevel()
signupas.geometry('300x200')
tkWindow.title("database program")
usernameLabel = Label(signupas, text="Username").grid(row=0, column=0)
username = StringVar()
usernameEntry = Entry(signupas, textvariable=username).grid(row=0, column=1)
passwordLabel = Label(signupas,text="Password").grid(row=1, column=0)
password = StringVar()
passwordEntry = Entry(signupas, textvariable=password, show='*').grid(row=1, column=1)
var1 = IntVar()
Checkbutton(signupas, text="2step verification", variable=var1).grid(row=2)
SignUp = partial(checkuser_email, username, password, var1)
updates = partial(update, var1)
updateButton = Button(signupas, text="Update", command=updates).grid(row=5, column=2)
signupButton = Button(signupas, text="SignUp", command=SignUp).grid(row=5, column=1)
signupas.mainloop()
Thanks in advance :)

Tkinter: How to pass arguments from Entry widgets to function?

I have created two Entry widgets called name_entry and passwd_entry. After the user enters his name and password, the program should subsequently list it if the user clicks on the Submit button.
Unfortunately this is not working. I'm trying to write it within a class and to pass it as an argument to my submit function.
I receive this error:
File "/usr/lib/python3.7/tkinter/__init__.py", line 1705, in __call__
return self.func(*args)
TypeError: submit() missing 2 required positional arguments: 'var_name' and 'var_passwd'
Code:
#/usr/bin/python3.7
from tkinter import *
class Window (Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("GUI")
self.pack(fill=BOTH, expand=1)
var_name = StringVar()
var_passwd = StringVar()
name = Label(self, text="Name: ")
name.place(x = 0, y = 0)
name_entry = Entry(root, textvariable = var_name)
name_entry.place(x = 90, y =0)
passwd = Label(self, text="Password: ")
passwd.place(x = 0, y = 90)
passwd_entry = Entry(root, textvariable = var_passwd)
passwd_entry.place(x = 90, y = 90)
Knop1 = Button(self, text="Submit", command=self.submit)
Knop1.place(x = 180, y=180)
def submit (self, var_name, var_passwd):
naam = var_name.get()
var_passwd = var_passwd.get()
print("The name is: ", naam)
print("The password is: ", var_passwd)
root = Tk()
root.geometry("500x300")
app = Window(root)
app.mainloop()
Can anyone help me? I'm also looking for a good Tkinter tutorial where OOP is being used.
You haven't passed the variables to the submit function button. For simple cases like this, you can use a lambda expression as a link between Tkinter and the callback function, otherwise Python will call the callback function before creating the widget: https://effbot.org/zone/tkinter-callbacks.htm
from tkinter import *
class Window (Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("GUI")
self.pack(fill=BOTH, expand=1)
var_name = StringVar()
var_passwd = StringVar()
name = Label(self, text="Name: ")
name.place(x = 0, y = 0)
name_entry = Entry(root, textvariable = var_name)
name_entry.place(x = 90, y =0)
passwd = Label(self, text="Password: ")
passwd.place(x = 0, y = 90)
passwd_entry = Entry(root, textvariable =var_passwd)
passwd_entry.place(x = 90, y = 90)
# Changed this line
Knop1 = Button(self, text="Submit", command=lambda: self.submit(var_name, var_passwd))
Knop1.place(x = 180, y=180)
def submit (self, var_name, var_passwd):
naam = var_name.get()
var_passwd = var_passwd.get()
print("The name is: ", naam)
print("The password is: ", var_passwd)
root = Tk()
root.geometry("500x300")
app = Window(root)
app.mainloop()
To address your question about OOP with tkinter, this question has some good advice: Best way to structure a tkinter application?
As a general rule it's best of the command of a button calls a function that accepts no arguments. Since you've made a special-purpose function that always operates on the same variables, you can have the directly access the variables.
First, make the variables an attribute of the class:
def init_window(self):
...
self.var_name = StringVar()
self.var_passwd = StringVar()
..
Then, define your function to access those variables:
def submit (self):
naam = self.var_name.get()
var_passwd = self.var_passwd.get()
...
And finally, modify how your button calls this function:
Knop1 = Button(self, text="Submit", command=self.submit)
Note: if you're not using the special properties of a tkinter variable (such as the trace mechanism), you don't need to use StringVar at all.
Example:
def init_window(self):
...
self.name_entry = Entry(root, textvariable = var_name)
self.passwd_entry = Entry(root, textvariable =var_passwd)
...
def submit (self):
naam = self.name_entry.get()
var_passwd = self.passwd_entry.get()
...

How to return entry value from another class?

I am trying to return a value from an Entry widget from another class.
My idea is, when the user has logged in successfully, the welcome screen will show the username that has just logged in.
I have tried using this:
self.userLogged = Label(main, text = self.entry_username.get())
self.userLogged.pack()
i tried linking >self.entry.entry_username.get() from the login class. But here is the error code:
AttributeError: 'App' object has no attribute 'entry_username'
Where I'm I going wrong?
Here is the full code:
from tkinter import *
import tkinter.ttk as ttk
class App():
def __init__(self,master):
notebook = ttk.Notebook(master)
notebook.pack(expand = 1, fill = "both")
#Frames
main = ttk.Frame(notebook)
notebook.add(main, text='Welcome Screen')
self.userLogged = Label(main, text = self.entry_username.get())
self.userLogged.pack()
###################################################################################################################################
##USERS##
###################################################################################################################################
class login(Frame):
def __init__(self, master):
super().__init__(master)
self.label_username = Label(self, text="Username: ",font=("bold",16))
self.label_password = Label(self, text="Password: ",font=("bold",16))
self.entry_username = Entry(self, font = ("bold", 14))
self.entry_password = Entry(self, show="*", font = ("bold", 14))
self.label_username.grid(row=0, sticky=E)
self.label_password.grid(row=1, sticky=E)
self.entry_username.grid(row=0, column=1)
self.entry_password.grid(row=1, column=1)
self.logbtn = Button(self, text="Login", font = ("bold", 10), command=self._login_btn_clicked)
self.logbtn.grid(columnspan=2)
self.pack()
def _login_btn_clicked(self):
# print("Clicked")
username = self.entry_username.get()
password = self.entry_password.get()
# print(username, password)
account_list = [line.split(":", maxsplit=1) for line in open("passwords.txt")]
# list of 2-tuples. Usersnames with colons inside not supported.
accounts = {key: value.rstrip() for key, value in account_list}
# Convert to dict[username] = password, and slices off the line ending.
# Does not support passwords ending in whitespace.
if accounts[username] == password:
self.label_username.grid_forget()
self.label_password.grid_forget()
self.entry_username.grid_forget()
self.entry_password.grid_forget()
self.logbtn.grid_forget()
self.pack_forget()
app = App(root)
else:
print("error")
root = Tk()
root.minsize(950, 450)
root.title("test")
lf = login(root)
root.mainloop()
When working with multiple classes in tkinter it is often a good idea to use class inherancy for the main window and frames. This allows us to use self.master to interact between classes.
That said you have a few things to change. You are using self where it is not needed and you should be doing import tkinter as tk to prevent overwriting of methods.
I have added a class to your code so we use one class for the root window. Then use one class for the login screen and then use one class for the frame after login.
import tkinter as tk
import tkinter.ttk as ttk
class NotebookFrame(tk.Frame):
def __init__(self, username):
super().__init__()
notebook = ttk.Notebook(self)
notebook.pack(expand=1, fill="both")
main = ttk.Frame(notebook)
notebook.add(main, text='Welcome Screen')
tk.Label(main, text=username).pack()
class Login(tk.Frame):
def __init__(self):
super().__init__()
tk.Label(self, text="Username: ", font=("bold", 16)).grid(row=0, sticky='e')
tk.Label(self, text="Password: ", font=("bold", 16)).grid(row=1, sticky='e')
self.entry_username = tk.Entry(self, font=("bold", 14))
self.entry_password = tk.Entry(self, show="*", font=("bold", 14))
self.entry_username.grid(row=0, column=1)
self.entry_password.grid(row=1, column=1)
tk.Button(self, text="Login", font=("bold", 10), command=self.master._login_btn_clicked).grid(columnspan=2)
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("test")
self.minsize(950, 450)
self.login_frame = Login()
self.login_frame.pack()
def _login_btn_clicked(self):
username = self.login_frame.entry_username.get()
password = self.login_frame.entry_password.get()
account_list = [line.split(":", maxsplit=1) for line in open("passwords.txt")]
accounts = {key: value.rstrip() for key, value in account_list}
if accounts[username] == password:
self.login_frame.destroy()
NoteFrame = NotebookFrame(username)
NoteFrame.pack()
else:
print("error")
if __name__ == "__main__":
App().mainloop()
Firstly, you should change class name from class login(Frame) to class Login(Frame).
Before fixing it, you called the login function from App, but you need to call Login class and use it.
class App:
def __init__(self, master):
notebook = ttk.Notebook(master)
notebook.pack(expand=1, fill="both")
# Frames
main = ttk.Frame(notebook)
notebook.add(main, text='Welcome Screen')
# `entry_username.get()` method is owned by the Login class,
# so you need to call from not `self(App class)` but `login(Login class)`.
login = Login(master) # Call Login class
self.userLogged = Label(main, text=login.entry_username.get())
self.userLogged.pack()
With this fix, I could call the Welcome screen.

Python Tkinter - processing data entered by a user

I want to create a program in Python with Tkinter GUI, and I want it to take string inputs from a user, then I want to do some operations on these strings - in this case, I want to mix parts of two words and get a new word. How can I handle this data entered by a user and use it to receive the result? Below is my code. I couldn't find the answer to this problem and nothing I tried works.
from Tkinter import *
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def init_window(self):
self.master.title("Mix words")
self.pack(fill=BOTH, expand=1)
menu = Menu(self.master)
self.master.config(menu=menu)
entryLbl1 = Label(self, text="Write the first word: ")
entryLbl1.pack()
self.entrytext1 = StringVar()
Entry(self, textvariable=self.entrytext1).pack()
self.buttontext1 = StringVar()
self.buttontext1.set("OK")
Button(self, textvariable=self.buttontext1, command=self.clicked1).pack()
self.label1 = Label(self, text="")
self.label1.pack()
global user_entry1
user_entry1 = self.entrytext1.get()
entryLbl2 = Label(self, text="Write the second word: ")
entryLbl2.pack()
self.entrytext2 = StringVar()
Entry(self, textvariable=self.entrytext2).pack()
self.buttontext2 = StringVar()
self.buttontext2.set("OK")
Button(self, textvariable=self.buttontext2, command=self.clicked2).pack()
self.label2 = Label(self, text="")
self.label2.pack()
global user_entry2
user_entry2 = self.entrytext2.get()
entryLbl3 = Label(self, text="Result: ")
entryLbl3.pack()
self.buttontext3 = StringVar()
self.buttontext3.set("Result")
Button(self, textvariable=self.buttontext1, command=self.clicked3).pack()
self.label3 = Label(self, text="")
self.label3.pack()
def clicked1(self):
input = self.entrytext1.get()
self.label1.configure(text=input)
def clicked2(self):
input = self.entrytext2.get()
self.label2.configure(text=input)
def clicked3(self):
self.user_entry1 = user_entry1
self.user_entry2 = user_entry2
first2a = user_entry1[0:2]
rest_a = user_entry1[2:]
first2b = user_entry2[0:2]
rest_b = user_entry2[2:]
input = first2b + rest_a + " " + first2a + rest_b
self.label3.configure(text=input)
root = Tk()
root.iconbitmap("py.ico")
root.geometry("600x300")
app = Window(root)
root.mainloop()
You need Entry() objects.
The following will show two Entry widgets and a Button.
When the button is pressed, the contents of both of the Entry objects will be printed to the console:
import sys
# Determine if you're running Python 3
is_py_3 = sys.version[0] == '3'
# Import Tkinter for the correct version of Python
if is_py_3:
from tkinter import Button, Entry, Tk
else:
from Tkinter import Button, Entry, Tk
class GUI:
def __init__(self):
# Set up the "Root" or "Parent" of the window.
self.root = Tk()
# Set up two "Entry" widgets.
self.entry1 = Entry(self.root)
self.entry1.insert(0, "Enter something here.")
self.entry2 = Entry(self.root)
self.entry2.insert(0, "and here...")
# Set up a button to handle the event.
self.button = Button(self.root, text="CLICK ME", command=self.onClicked)
self.entry1.pack()
self.entry2.pack()
self.button.pack()
def onClicked(self):
# Print the contents of the entry widgets.
s1 = self.entry1.get()
s2 = self.entry2.get()
print(s1, s2)
app = GUI()
app.root.mainloop()

Categories