I am new to tkinter and object oriented programming. For some reason when run the following code and put in admin/password, instead of switching frames, it gives the following error:
Exception in Tkinter callback Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__
return self.func(*args) File "H:\Networ\multiwindowguiskeleton.py", line 44, in checkpassword
controller.show_frame(messagescreenpagevar)
NameError: name 'controller' is not defined
The code is:
import tkinter as tk
class Guiroot(tk.Tk):
def __init__(self,*args,**kwargs):
tk.Tk.__init__(self,*args,**kwargs)
framecontainer = tk.Frame(self)
framecontainer.pack(side="top",fill="both",expand=True)
framecontainer.grid_rowconfigure(0,weight=1)
framecontainer.grid_columnconfigure(0,weight=1)
self.title("Vault Messenger")
self.frames = {}
passwordpagevar = passwordpage(framecontainer,self) # this is adding the different pages to a list so they can be called forward later.
messagescreenpagevar = messagescreen(framecontainer,self)
self.frames[passwordpagevar] = passwordpagevar
self.frames[messagescreenpagevar] = messagescreenpagevar
passwordpagevar.grid(row=0 , column = 0, sticky = "nsew")
messagescreenpagevar.grid(row=0 , column = 0, sticky = "nsew")
self.show_frame(passwordpagevar)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
class passwordpage(tk.Frame):
def checkpassword(self):
if self.usernamebox.get() == "admin" and self.passwordbox.get() == "password":
self.errorlabel['text'] = "Correct entry/pass"
controller.show_frame(messagescreenpagevar)
else:
self.errorlabel['text'] = "Incorrect entry/pass"
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
self.usernamelabel = tk.Label(self,text="Username:")
self.usernamebox = tk.Entry(self)
self.passwordlabel = tk.Label(self, text="Password:")
self.passwordbox = tk.Entry(self,show="*")
self.errorlabel = tk.Label(self, text = "")
self.enterdetails = tk.Button(self, text = "Enter", command = self.checkpassword)
self.usernamelabel.grid(row=0)
self.usernamebox.grid(row=1)
self.passwordlabel.grid(row=2)
self.passwordbox.grid(row=3)
self.errorlabel.grid(row=4)
self.enterdetails.grid(row=5)
class messagescreen(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
self.userlist = tk.Listbox(self, width = 20, height = 20)
self.chatbox = tk.Text(self, width = 50,height = 20)
self.chatentry = tk.Entry(self, width = 60)
self.sendmessagebutton = tk.Button(self, text = "Send")
self.userlist.grid(row=0,column=0)
self.chatbox.grid(row=0,column=1, columnspan = 2)
self.chatentry.grid(row=1,column=1)
self.sendmessagebutton.grid(row=1,column= 2)
root = Guiroot()
root.mainloop()
In line 44, the interpreter finds the following expression
controller.show_frame(messagescreenpagevar)
In this scope, controller was not defined. That's why the interpreter prompts the error name 'controller' is not defined.
Python uses lexical scope. So in order to have a variable controller defined at line 44, you would either have to define it in:
the method checkpassword
the class passwordpage
in the global scope of your module
Related
I'm trying to make a simple login GUI with tkinter but I keep getting this error :
AttributeError: type object 'LoginApp' has no attribute 'frames'
This is the code for my LoginApp class :
class LoginApp(tkinter.Tk):
def __init__(self, *args, **kwargs):
tkinter.Tk.__init__(self, *args, **kwargs)
container = tkinter.Frame(self)
container.pack(side='top',fill='both',expand=True)
container.grid_rowconfigure(0, weight=1)
container.grid_columnconfigure(0, weight=1)
self.frames = {}
for F in (StartPage, LogPage, RegPage):
self.frame = F(container, self)
self.frames[F] = self.frame
self.frame.grid(row=0, column=0, sticky='nesw')
self.showFrame(StartPage)
def showFrame(self, cont):
self.frame = self.frames[cont]
self.frame.tkraise()
and this is my RegPage class:
class RegPage(tkinter.Frame):
def __init__(self, parent, controller):
tkinter.Frame.__init__(self, parent)
self.userReg = tkinter.StringVar()
self.pwdReg1 = tkinter.StringVar()
self.pwdReg2 = tkinter.StringVar()
label = tkinter.Label(self,text='Enter details below: ')
label.pack(pady=10,padx=10)
userLabel = tkinter.Label(self,text='Username * ')
userLabel.pack()
userEntry = tkinter.Entry(self,textvariable=self.userReg)
userEntry.focus()
userEntry.pack()
pwd1Label = tkinter.Label(self,text='Password * ')
pwd1Label.pack()
pwdEntry1 = tkinter.Entry(self,textvariable=self.pwdReg1,show='*')
pwdEntry1.pack()
pwd2Label = tkinter.Label(self,text='Re-enter Password * ')
pwd2Label.pack()
pwdEntry2 = tkinter.Entry(self,textvariable=self.pwdReg2,show='*')
pwdEntry2.pack()
regButton = tkinter.Button(self,text='Register',width=5,height=1,command=lambda: self.regUser(LoginApp))
regButton.pack(side='right')
backButton = tkinter.Button(self,text='Back',width=5,height=1,command=lambda: controller.showFrame(StartPage))
backButton.pack(side='left')
self.resLabel = tkinter.Label(self,text='')
self.resLabel.pack()
def regUser(self, controller):
user = self.userReg.get()
pwd1 = self.pwdReg1.get()
pwd2 = self.pwdReg2.get()
logInfo = pickle.load(open('users.p','rb'))
if user in logInfo:
self.resLabel.config(text='User already exists',fg='red')
else:
if pwd1 == pwd2:
logInfo.update( {user: pwd1} )
pickle.dump(logInfo, open('users.p','wb'))
self.resLabel.config(text='User registered',fg='green')
controller.showFrame(controller, StartPage)
This is the full error message :
File "/usr/lib/python3.8/tkinter/__init__.py", line 1883, in __call__
return self.func(*args)
File "/home/qumquat/coding/github/python/projects/self/login/gui/test.py", line 101, in <lambda>
regButton = tkinter.Button(self,text='Register',width=5,height=1,command=lambda: self.regUser(LoginApp))
File "/home/qumquat/coding/github/python/projects/self/login/gui/test.py", line 123, in regUser
controller.showFrame(controller, StartPage)
File "/home/qumquat/coding/github/python/projects/self/login/gui/test.py", line 27, in showFrame
self.frame = self.frames[cont]
AttributeError: type object 'LoginApp' has no attribute 'frames'
I know it's that last line where I try and call showFrame that is wrong but I don't understand why because the function works perfectly with the back button.
Sorry if there has already been a post like this but I couldn't find any.
I'm trying to call a String from a entry box in another class to a public Var. The code for calling the Var seams to work fine but got a Error ''' image "pyimage5" doesn't exist''' on my second class sins i added the new lines of code. Everything was working fun before.
Lines of code I added:
class StartPage(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
class PageOne(tk.Frame):
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent,bg=Gray_Back_Page_1)
to
class StartPage(tk.Frame):
def __init__(self, parent, controller):
super(StartPage,self).__init__()
class PageOne(tk.Frame):
def __init__(self, parent, controller):
super(PageOne,self).__init__(parent,bg=Gray_Back_Page_1)
and added the following code outside a class
StartPage_object = StartPage(tk.Frame, SeaofBTCapp)
USER = StartPage_object.Username_Text.get()
PASSWORD = StartPage_object.Password_Text.get()
The image code Var = Image.open(Image_File +"\File_Name.png") seams to work in my Start Page but gives me an Error in my Page One
Please see complete code below:
desktop = os.path.expanduser("~\Desktop")
Image_File = os.path.expanduser("~\Desktop\file")
#===============Frame==========================Container====================>
class SeaofBTCapp(tk.Tk,object):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
tk.Tk.wm_title(self, "Name")
tk.Tk.geometry(self,"1360x728")
tk.Tk.iconbitmap(self, default= desktop + "\icon.ico")
self.resizable(False, False)
#tk.Tk.overrideredirect(False)
container = tk.Frame(self)
container.pack(side="top", fill="both", expand = True)
container.grid_rowconfigure(0, weight=10)
container.grid_columnconfigure(0, weight=10)
self.frames = {}
for F in (StartPage, PageOne):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row=0, column=0, sticky="nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
#===============Start=========================Page====================>
class StartPage(tk.Frame):
def __init__(self, parent, controller):
super(StartPage,self).__init__()
#=============Set_Background==================>
load1 = Image.open(Image_File +"\Login_Bcakground.png")
render1 =ImageTk.PhotoImage(load1)
#========= Reset_username & Password ===========>
self.Username_Text= tk.StringVar()
self.Password_Text= tk.StringVar()
#==== Creating Buttons, Entry Box and Labels with there commands =====>
User_Name_Entry = tk.Entry(self,textvariable = self.Username_Text, fg =
Entry_Box_Text_Colour,bg =
Entry_Box_Back_White,borderwidth = 0,
font=Normal_Text,width = 30)
User_Name_Entry.place(x=795,y=282)
User_Pass_Entry = tk.Entry(self,textvariable = selfPassword_Text, fg =
Entry_Box_Text_Colour,bg =
Entry_Box_Back_White,borderwidth = 0,
font=Normal_Text,width = 30)
User_Pass_Entry.place(x=795,y=329)
#===============Login==========================Var====================>
StartPage_object = StartPage(tk.Frame, SeaofBTCapp)
USER = StartPage_object.Username_Text.get()
PASSWORD = StartPage_object.Password_Text.get()
#===============Page==========================One====================>
class PageOne(tk.Frame):
def __init__(self, parent, controller):
super(PageOne,self).__init__(parent,bg=Gray_Back_Page_1)
photo = ImageTk.PhotoImage(Image.open(Image_File +"\Splach_Page.png"))
vlabel=tk.Label(self,text = "",image=photo)
vlabel.image = photo
vlabel.place (x=-1,y=-5,relwidth=1, relheight=1)
Error Lines:
image "pyimage5" doesn't exist
Stack trace:
> File "C:\Users\MainUser\source\v_1_1.py", line 251, in __init__
> vlabel=tk.Label(self,text = "",image=photo)
> File "C:\Users\MainUser\source\v_1_1.py", line 93, in __init__
> frame = F(container, self)
> File "C:\Users\MainUser\source\v_1_1.py", line 2736, in <module>
> app = SeaofBTCapp()
Loaded '__main__'
for me, the problem was with Spyder not the code.
I changed to Jupyter Notebook and it worked as expected
This looks like a known bug in tkinter, where the python garbage collector deletes the photo. To prevent this, you need to create a global reference to the image. Something like this should work:
class PageOne(tk.Frame):
images = []
def __init__(self, parent, controller):
super(PageOne,self).__init__(parent,bg=Gray_Back_Page_1)
photo = ImageTk.PhotoImage(Image.open(Image_File +"\Splach_Page.png"))
PageOne.images.append(photo)
vlabel=tk.Label(self,text = "",image=photo)
vlabel.image = photo
vlabel.place (x=-1,y=-5,relwidth=1, relheight=1)
Hope that works for you!
This did not work and give me the same error, but your idea helped me to solve it in another way. I went back to my original code and solved my first issue with the list methods.
#=============Use_List_For_Capturing_Var_In_Classes==================
Name_oF_User_Loged_In = []
Name_oF_User_Loged_In.append("User Name")
class StartPage(tk.Frame):
global login_data_Pass
global login_data_User
global Name_oF_User_Loged_In
def __init__(self, parent, controller):
tk.Frame.__init__(self,parent)
#=============Set_Background==================>
load1 = Image.open(Image_File +"\Login_Bcakground.png")
render1 =ImageTk.PhotoImage(load1)
def Login_Check():
USER1 = self.Username_Text.get()
PASSWORD1 = self.Password_Text.get()
login_data_Pass.pop(0)
login_data_User.pop(0)
login_data_Pass.append(PASSWORD1)
login_data_User.append(USER1)
#==== Creating Buttons, Entry Box and Labels with there commands =====>
Login_button = tk.Button(self, text="Login",
fg="#d0cece",bg="#3f9a84",borderwidth = 0, font=Normal_Text,height
=1,width = 10,
command=lambda: Login_Check())
Login_button.place(x=1010,y=380)
User_Name_Entry = tk.Entry(self,textvariable = self.Username_Text, fg =
Entry_Box_Text_Colour,bg =
Entry_Box_Back_White,borderwidth = 0,
font=Normal_Text,width = 30)
User_Name_Entry.place(x=795,y=282)
User_Pass_Entry = tk.Entry(self,textvariable = selfPassword_Text, fg =
Entry_Box_Text_Colour,bg =
Entry_Box_Back_White,borderwidth = 0,
font=Normal_Text,width = 30)
User_Pass_Entry.place(x=795,y=329)
class PageOne(tk.Frame):
global login_data_Pass
global login_data_User
global Name_oF_User_Loged_In
def __init__(self, parent, controller):
tk.Frame.__init__(self, parent,bg=Gray_Back_Page_1)
photo = ImageTk.PhotoImage(Image.open(Image_File +"\Splach_Page.png"))
vlabel=tk.Label(self,text = "",image=photo)
vlabel.image = photo
vlabel.place (x=-1,y=-5,relwidth=1, relheight=1)
user = login_data_User[0]
password = login_data_Pass[0]
In my GUI, i wanted to display an image that changes depending on some value. The image would change between self.img1 and self.img2. I created separate classes for the container and the pages. The container is defined as such:
class Gui(Tk):
def __init__(self, *args, **kwargs):
Tk.__init__(self, *args, **kwargs)
container = Frame(self)
container.pack(side="top", fill = "both", expand = TRUE)
container.grid_rowconfigure(0, weight = 1)
self.MyReading = StringVar()
self.redpic = Image.open("red.png")
self.redpic = self.redpic.resize((100,100), Image.ANTIALIAS)
self.greenpic = Image.open("green.png")
self.greenpic = self.greenpic.resize((100,100), Image.ANTIALIAS)
self.img1 = ImageTk.PhotoImage(self.redpic)
self.img2 = ImageTk.PhotoImage(self.greenpic)
self.frames={}
for F in (StartPage, PageOne):
frame = F(container, self)
self.frames[F] = frame
frame.grid(row = 0, column = 0, sticky = "nsew")
self.show_frame(StartPage)
def show_frame(self, cont):
frame = self.frames[cont]
frame.tkraise()
And the page displaying the image:
class StartPage(Frame):
def __init__(self, parent, controller):
Frame.__init__(self,parent)
label = Label(self, text="StartPage")
label.grid()
label1 = Label(self, textvariable = controller.MyReading)
label1.grid();
self.label4 = Label(self, image = controller.img1)
self.label4.grid();
self.label4.image = controller.img1
button1 = Button (self, text = "Show PageOne", command = lambda: controller.show_frame(PageOne))
button1.grid()
It is currently displaying img1. Now, to instantiate the GUI:
root = Gui()
update_reading()
root.mainloop()
update_reading() updates my other labels defined with StringVar(). I was wondering how would I go about updating label4 (which shows the image) if I can only instantiate/get access to Gui()? I only know that I could change the label4 through configure(). Is there a textvariable equivalent for images?
EDIT: I forgot to put the logic that I wanted to implement. It is basically:
If foo == TRUE:
--change the image to img1--
else:
--change the image to img2--
for some foo that exists outside of Gui.
EDIT2: Following through a previous comment's logic, I made some small changes to the code In the Gui:
class Gui(Tk):
def __init__(self, *args, **kwargs):
self.ColorVar = DoubleVar()
And within StartPage(), the changes are:
class StartPage(Frame):
def __init__(self, parent, controller):
controller.ColorVar.trace("w",self.IdkChief(controller))
def IdkChief(self, controller):
global val1
if float(val1) < 2.50 :
self.label4.configure(image = controller.img2)
self.label4.image = controller.img2
else:
self.label4.configure(image = controller.img1)
self.label4.image = controller.img1
Then the changes on ColorVar is defined in update_reading()as such:
def update_reading():
global val1
root.ColorVar.set(val1)
root.after(100,update_reading)
Where val1 is a changing float value. I decided to change it from a boolean logic to a float one to increase flexibility. It would then throw me a generic error
Exception in Tkinter callback Traceback (most recent call last):
File
"C:\Users\AppData\Local\Programs\Python\Python37\lib\tkinter__init__.py",
line 1705, in call
return self.func(*args) TypeError: 'NoneType' object is not callable
This error would repeat until the GUI is closed.
You can use tkinter variable trace function to set up a callback function to be executed whenever the variable is updated. Inside the callback function, you can then update the label based on the value of the variable.
Below is sample code blocks (based on your posted code design) to achieve your goal:
class Gui:
def __init__(self, *args, **kwargs):
...
self.ColorVar = DoubleVar()
...
class StartPage(Frame):
def __init__(self, parent, controller):
...
# register a callback to be executed whenever variable is modified
controller.ColorVar.trace('w', lambda *args: self.IdkChief(controller))
def IdkChief(self, controller):
img = controller.img1 if controller.ColorVar.get() < 2.5 else controller.img2
self.label4.config(image=img)
In my program snippet I create a python window with 2 fields and 3 buttons. The left two buttons should perform some action but instead an error is thrown:
Exception in Tkinter callback
Traceback (most recent call last):
File "/usr/lib64/python3.4/tkinter/__init__.py", line 1538, in __call__
return self.func(*args)
File ".../GuiFile.py", line 11, in <lambda>
self.F[2] = ButtonClass().make_button(stacked="left",buttontext= "Action button", buttoncommand = lambda: cf.mainButtons.doButtonAction1(self))
File ".../ClassFile.py", line 11, in doButtonAction1
print(gf.StartGui.F[0].textField.get("1.0","end-1c"))
AttributeError: 'NoneType' object has no attribute 'textField'
Why is dict item F[0] (created in line 9 of GuiFile.py) not recognized as Text() class with the attribute textField (defined in line 43 of GuiFile.py)?
MainProgramFile.py
#!/usr/bin/env python3
import sys
import ClassFile
import GuiFile as gf
if __name__== '__main__':
gf.StartGui().mainloop()
GuiFile.py
import sys
from tkinter import *
import ClassFile as cf
class StartGui(Frame):
F = {}
def __init__(self,parent=None):
Frame.__init__(self, parent)
self.F[0] = FieldTextClass().make_field(labeltext="Label of field 1", fieldtext="veld 1", fieldheight=90)
self.F[1] = FieldTextClass().make_field(labeltext="Label of field 2", fieldtext="veld 2")
self.F[2] = ButtonClass().make_button(stacked="left",buttontext= "Action button", buttoncommand = lambda: cf.mainButtons.doButtonAction1(self))
self.F[3] = ButtonClass().make_button(stacked="left", buttontext= "Exchange button", buttoncommand = lambda: cf.mainButtons.doButtonSwitchValues(self))
self.F[4] = ButtonClass().make_button(stacked="right",buttontext= "Quit button",buttoncommand = lambda: cf.mainButtons.doButtonQuit(self))
self.pack(expand=True, fill=BOTH, anchor="nw", side=LEFT)
#for i in range(self.F.__len__()): print(self.F[i].__class__,self.F[i].objectType)
class ButtonClass (Frame, Button):
objectType = "button"
def make_button(self, parent=None, stacked="horizontal", buttontext="Button", buttonwidth=120, buttonheight=32, buttoncommand=""):
self.buttonwidth=buttonwidth
self.buttonheight=buttonheight
self.buttontext=buttontext
self.buttoncommand=buttoncommand
if stacked=="vertical":
BUTTONSTACK = TOP
elif stacked=="right":
BUTTONSTACK = RIGHT
elif stacked=="horizontal" or stacked=="left":
BUTTONSTACK = LEFT
else:
BUTTONSTACK = LEFT
self.top = Frame(parent, height=self.buttonheight, width=self.buttonwidth)
self.top.pack_propagate(False)
self.top.pack(side=BUTTONSTACK)
button = Button(self.top, text=self.buttontext, command=self.buttoncommand,height=self.buttonheight, width=self.buttonwidth)
button.pack(fill=BOTH)
class FieldTextClass(Frame,Text,Label):
textField = None
objectType = "inputField"
def make_field(self, parent=None, labeltext="Empty", fieldtext="Empty", fieldwidth=600, fieldheight=20, labelwidth=120, labelheight=20):
self.fieldheight=fieldheight
self.fieldwidth=fieldwidth
self.fieldtext=fieldtext
self.labeltext=labeltext
self.labelheight=labelheight
self.labelwidth=labelwidth
self.top = Frame(parent)
#create the label, whith the text shifted left/top in a separate Frame
labelFrame = Frame(self.top, height = self.labelheight,width=self.labelwidth)
label = Label(labelFrame, text=self.labeltext, fg="black", anchor="nw")
label.pack(expand=True, fill=BOTH, anchor="nw", side=LEFT)
labelFrame.pack_propagate(False)
labelFrame.pack(side=LEFT, anchor="nw")
#create the text field, packed in a separate Frame
fieldFrame = Frame(self.top, height = self.fieldheight,width=self.fieldwidth)
self.textField = Text(fieldFrame, fg="black",bg="white")
self.textField.insert(INSERT,self.fieldtext)
self.textField.pack(expand=True, fill=BOTH, side=LEFT)
fieldFrame.pack_propagate(False)
fieldFrame.pack(side=LEFT)
self.top.pack(side=TOP)
ClassFile.py
import sys
from tkinter import *
import GuiFile as gf
class mainButtons():
def doButtonQuit(self):
print("Quitting test via ClassFile")
self.quit()
def doButtonAction1(self):
print(gf.StartGui.F[0].textField.get("1.0","end-1c"))
print(gf.StartGui.F[1].textField.get("1.0","end-1c"))
gf.StartGui.F[0].textField.delete("1.0","end")
gf.StartGui.F[0].textField.insert(INSERT, "New text")
def doButtonSwitchValues(self):
tmp0=gf.StartGui.F[0].textField.get("1.0","end-1c")
tmp1=gf.StartGui.F[1].textField.get("1.0","end-1c")
gf.StartGui.F[0].textField.delete("1.0","end")
gf.StartGui.F[0].textField.insert(INSERT, tmp1)
gf.StartGui.F[1].textField.delete("1.0","end")
gf.StartGui.F[1].textField.insert(INSERT, tmp0)
When you do ButtonClass().make_button() (or FieldTextClass.make_field()) , python will return the value of the function, not the instance of the class. The function returns None, so the dictionary elements are None.
The way you're using the custom classes is very strange. Instead of creating special functions, put that code in an __init__, and use the class like you would any other class.
For example:
class ButtonClass (Frame):
def __init__(self, parent=None, stacked="horizontal",
buttontext="Button", buttonwidth=120, buttonheight=32,
buttoncommand=""):
Frame.__init__(self, parent)
self.buttonwidth=buttonwidth
...
...
self.F[2] = ButtonClass(stacked="left",buttontext= "Action button", buttoncommand = lambda: cf.mainButtons.doButtonAction1(self))
Note: when doing it this way, you don't have to create a separate frame inside __init__ (ie: self.top), since self is itself already a Frame.
I have been having lots of problems with this code, it is giving me a weird error. It occurs when I attempt to close the program; I get this error(shown at the bottom ). I also previously before adding the .protocol but was getting an error to do with the module. Is it the way I have imported tkinter? Or what I am attempting to destroy?
import tkinter.ttk
from tkinter.constants import *
from tkinter import *
class App(ttk.Frame):
#classmethod
def main(cls):
GUI = tkinter.Tk()
app = cls(GUI)
app.grid(sticky=NSEW)
GUI.grid_columnconfigure(0, weight=1)
GUI.grid_rowconfigure(0, weight=1)
GUI.resizable(True, False)
GUI.mainloop()
self.protocol("WM_DELETE_WINDOW", self.destroy())
GUI.protocol("WM_DELETE_WINDOW", GUI.destroy())
def __init__(self, GUI):
super().__init__(GUI)
self.create_variables()
self.create_widgets()
self.grid_widgets()
self.grid_columnconfigure(0, weight=1)
def create_variables(self):
pass
def create_widgets(self):
self.Logo = tkinter.PhotoImage(file="Logo.gif")
self.x = Label(image=self.Logo)
##Top bar Widgets##
self.button1 =ttk.Button(self, text="Profile", command=self.GetProfile)
if self.CheckLogin() == False:
self.button2 = ttk.Button(self, text="Log in", command=self.Login)
self.button3 = ttk.Button(self, text="Download",command=self.download)
self.Label2 = ttk.Label(self,text="")
def grid_widgets(self):
options = dict(sticky=NSEW, padx=3, pady=4)
options1 = dict(sticky=N)
self.x.grid(column=0,row=1, **options1)
#top bar
self.button1.grid(column = 1,row = 1,**options1)
self.button2.grid(column = 2,row = 1,**options1)
self.button3.grid(column = 3,row = 1,**options1)
#To be completed functions
def download(self):
pass
def GetProfile(self):
pass
def Login(self):
if self.Logindefault() == True:
print("login here")
elif self.Logindefault() == False:
self.v = StringVar()
print("Not logged in.")
options = dict(sticky=NSEW, padx=3, pady=4)
self.t = Toplevel(self)
self.t.title("Login")
self.t.grid_columnconfigure(0, weight=1)
self.t.grid_rowconfigure(0, weight=1)
self.t.entry1 = ttk.Entry(self.t)
self.t.entry2 = ttk.Entry(self.t)
self.t.button1 = ttk.Button(self.t,text="login",command=self.destroy)
self.t.entry1.grid(column = 0 ,row = 0, **options)
self.t.entry1.insert(0,"Username")
self.t.entry2.grid(column = 0 ,row = 1, **options)
self.t.entry2.insert(0,"Password")
self.t.button1.grid(column = 1,row = 0,rowspan=2, **options)
self.t.checkbox = ttk.Checkbutton(self.t,text="Remember me",variable=self.v)
self.t.checkbox.grid(column =0,row=2,**options)
def destroy(self):
self.usernameGO = self.t.entry1.get()
self.passwordGO = self.t.entry2.get()
print(self.usernameGO,self.passwordGO,self.v)
self.t.destroy()
def CheckLogin(self):
return False #If not logged in.
def Logindefault(self):
try:
file = open("UserLog.txt","rt")
for i in file:
if i[0:6] =="__usr__":
self.username = i.sptrip("__usr__")
elif i[0:6] =="__pss__":
self.password = i.strip("__pss__")
return True
except Exception:
#username file not found
print("error")
return False
if __name__ == '__main__':
App.main()
Here is the error which I get when I try to close the main window:
Exception in Tkinter callback
Traceback (most recent call last):
File "C:\Python34\lib\tkinter\__init__.py", line 1533, in __call__
return self.func(*args)
File "C:\Python34\lib\tkinter\__init__.py", line 1892, in destroy
for c in list(self.children.values()): c.destroy()
File "C:\Users\charlie\Desktop\Yahtzee - Copy.py", line 74, in destroy
self.usernameGO = self.t.entry1.get()
AttributeError: 'App' object has no attribute 't'
self.protocol("WM_DELETE_WINDOW", self.destroy())
GUI.protocol("WM_DELETE_WINDOW", GUI.destroy())
Generally, when you register callback methods, you need to omit the parentheses. Otherwise, the methods will be called immediately, and their return values will be registered instead. This means that destroy will be executed before Login executes, so self.t won't yet exist. Try:
self.protocol("WM_DELETE_WINDOW", self.destroy)
GUI.protocol("WM_DELETE_WINDOW", GUI.destroy)