Keep getting a certain error with tkinter root.destroy - python

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)

Related

communication between tkinter toplevels

I'm working on a little project and made a little on-screen keyboard as a tkinter Toplevel
my application is buildt like this:
Root-Window (Tk-Widget)
input 1 (Entry-Widget)
input 2 (Entry-Widget)
input 3 (Text-Widget)
on_screen-keyboard (Toplevel-Widget)
the Toplevel-Widget contains Buttons, with callbacks that should enter text in the entries (just like keyboard-Buttons)
What I want is a communication between children of the keyboard/the keyboard and the last active input-Widget. My Problem is, that I don't know, how to say the keyboard, to which input-Widget it should send the message.
import tkinter as tk
from tkinter import ttk
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.active_input = tk.Variable(value=None)
ttk.Button(self, text="show Keyboard", command=lambda: Keyboard(self)).pack()
self.text = tk.StringVar(value="")
self.input1 = ttk.Entry(self)
self.input1.bind("<FocusIn>", lambda e: self.active_input.set(self.input1))
self.input2 = ttk.Entry(self)
self.input2.bind("<FocusIn>", lambda e: self.active_input.set(self.input2))
self.input3 = tk.Text(self, height=3, width=15)
self.input3.bind("<FocusIn>", lambda e: self.active_input.set(self.input3))
self.input1.pack()
self.input3.pack()
self.input2.pack()
class Keyboard(tk.Toplevel):
OPENED = False
NAME = "- Keyboard -"
NUM = [{"text":"1", "width":1},
{"text":"2", "width":1},
{"text":"3", "width":2}]
CHAR= [{"text":"A", "width":1},
{"text":"B", "width":1},
{"text":"C", "width":2}]
def __init__(self, master):
if not Keyboard.OPENED:
Keyboard.OPENED = True
print("keyboard opened!")
self.master = master
tk.Toplevel.__init__(self, master)
self.title(self.NAME)
self.protocol("WM_DELETE_WINDOW", self.close)
self.keyb_nb = ttk.Notebook(self)
self.keyb_nb.pack()
self.num_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.num_tab, Keyboard.NUM,2)
self.keyb_nb.add(self.num_tab, text="123")
self.char_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.char_tab, Keyboard.CHAR, 2)
self.keyb_nb.add(self.char_tab, text="ABC")
def createPad(self, master, pad:list, max_col):
self.co_count = 0
self.ro = 1
for button in pad:
button["id"] = ttk.Button(master, width=6*button["width"], text=button["text"], command=self.bclicked(button))
if self.co_count >= max_col:
self.ro = self.ro + 1
self.co_count = 0
button["id"].grid(row=self.ro, columnspan=button["width"], column=self.co_count)
self.co_count = self.co_count+button["width"]
def bclicked(self, button:dict):
"""
reciver = self.master.active_input #I think the Problem here is, that the variable contains a string, not a widget
reciever.focus_force()
reciever.insert(index=tk.INSERT, string=button["text"])
"""
pass
def close(self):
Keyboard.OPENED = False
self.destroy()
print("keyboard closed!")
root = MainWindow()
root.mainloop()
Here the init of the Mainwindow and the bclicked of the Keyboard class are important...
the code is debug-ready
I would prefer a solution, similar to the communication in the internet (sender=button, receiver-id, message), but very welcome every working solution
btw: I'm also looking for a solution, how I don't have to force the input to focus and the Toplevel stays an the highest layer of the screen (that if I focus the Tk-Widget/one of the inputs/the button, the keyboard will stay in front of it)
SUMMARY: how do I find out, which of the 3 input-widgets was active at last, when the keyboard-toplevel has already the focus?
I may made more changes than needed, but mainly focus on the method keyboard_triger() and pass_key_to_master(), this two use the idea that the variable master implements, having access to call methods out of scope.
Olso the method set_focused_object() stores a reference to the last object beeng focused, note than it stores the widget and not the event, it's easyer than searching each time the object
import tkinter as tk
from tkinter import ttk
class MainWindow(tk.Tk):
def keyboard_triger(self, key):
# to identify wath object is just use
# isinstance(self.active_input, ttk.Entry)
self.active_input.insert(tk.END, key)
def new_keyboard(self):
Keyboard(self)
def set_focused_object(self, event):
self.active_input = event.widget
def __init__(self):
tk.Tk.__init__(self)
self.active_input = None
ttk.Button(self, text="Show Keyboard", command=self.new_keyboard).pack()
self.input1 = ttk.Entry(self)
self.input1.bind("<FocusIn>", self.set_focused_object)
self.input1.pack()
self.input2 = ttk.Entry(self)
self.input2.bind("<FocusIn>", self.set_focused_object)
self.input2.pack()
self.input3 = tk.Text(self, height=3, width=15)
self.input3.bind("<FocusIn>", self.set_focused_object)
self.input3.pack()
class Keyboard(tk.Toplevel):
def pass_key_to_master(self, key):
self.master.keyboard_triger(key)
def __init__(self, master):
tk.Toplevel.__init__(self, master)
self.master = master
self.title('Keyboard')
# this way of agruping keys stores the kwags
# of the drawing method
keys = {
'A': {'x': 0, 'y': 0},
'B': {'x': 20, 'y': 20},
'C': {'x': 50, 'y': 50}
}
# expected structure
# {string key: reference to the button}
self.buttons = {}
for i in keys:
self.buttons[i] = tk.Button( # i=i is required to make a instance
self, text=i, command=lambda i=i: self.pass_key_to_master(i)
)
self.buttons[i].place(**keys[i])
if __name__ == '__main__':
root = MainWindow()
root.mainloop()
Your code maybe could have a better construction.(But I didn't revise your code construction.)
Followed by your code,I use a global variable.And fix some errors in your code.And it could work normally in my computer.
import tkinter as tk
from tkinter import ttk
class MainWindow(tk.Tk):
def __init__(self, *args, **kwargs):
tk.Tk.__init__(self, *args, **kwargs)
self.active_input = tk.Variable(value=None)
ttk.Button(self, text="show Keyboard", command=lambda: Keyboard(self)).pack()
global focusedWidget
focusedWidget = None
self.text = tk.StringVar(value="")
self.input1 = ttk.Entry(self)
self.input1.bind("<FocusIn>", self.getFocusWidget)
self.input2 = ttk.Entry(self)
self.input2.bind("<FocusIn>", self.getFocusWidget)
self.input3 = tk.Text(self, height=3, width=15)
self.input3.bind("<FocusIn>", self.getFocusWidget)
self.input1.pack()
self.input3.pack()
self.input2.pack()
def getFocusWidget(self,event): # this function could be a static function
global focusedWidget
focusedWidget = event.widget
class Keyboard(tk.Toplevel):
OPENED = False
NAME = "- Keyboard -"
NUM = [{"text":"1", "width":1},
{"text":"2", "width":1},
{"text":"3", "width":2}]
CHAR= [{"text":"A", "width":1},
{"text":"B", "width":1},
{"text":"C", "width":2}]
def __init__(self, master):
if not Keyboard.OPENED:
Keyboard.OPENED = True
print("keyboard opened!")
self.master = master
tk.Toplevel.__init__(self, master)
self.title(self.NAME)
self.protocol("WM_DELETE_WINDOW", self.close)
self.keyb_nb = ttk.Notebook(self)
self.keyb_nb.pack()
self.num_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.num_tab, Keyboard.NUM,2)
self.keyb_nb.add(self.num_tab, text="123")
self.char_tab = ttk.Frame(self.keyb_nb)
self.createPad(self.char_tab, Keyboard.CHAR, 2)
self.keyb_nb.add(self.char_tab, text="ABC")
def createPad(self, master, pad:list, max_col):
self.co_count = 0
self.ro = 1
for button in pad:
button["id"] = ttk.Button(master, width=6*button["width"], text=button["text"], command=lambda button=button:self.bclicked(button)) # this lambda expression has some errors.
if self.co_count >= max_col:
self.ro = self.ro + 1
self.co_count = 0
button["id"].grid(row=self.ro, columnspan=button["width"], column=self.co_count)
self.co_count = self.co_count+button["width"]
def bclicked(self, button:dict):
global focusedWidget
"""
reciver = self.master.active_input #I think the Problem here is, that the variable contains a string, not a widget
reciever.focus_force()
reciever.insert(index=tk.INSERT, string=button["text"])
"""
if not focusedWidget: # If user hasn't click a entry or text widget.
print("Please select a entry or text")
return
if focusedWidget.widgetName=='ttk::entry': # use if statement to check the type of selected entry.
focusedWidget.insert(index=tk.INSERT,string=button["text"])
else:
focusedWidget.insert("end",button["text"])
def close(self):
Keyboard.OPENED = False
self.destroy()
print("keyboard closed!")
root = MainWindow()
root.mainloop()

Cannot create menu AttributeError: 'Frame' object has no attribute 'tk_menuBar'

I am using the following snippet from a tutorial of Tkinter to create a Gui with a menu Bar. I copied exactly how it was in the tutorial:
from tkinter import *
from tkinter import Menu
from tkinter import Menubutton
def new_file():
pass
def open_file():
pass
def stub_action():
pass
def makeCascadeMenu():
CasBtn = Menubutton(mBar, text='Cascading Menus', underline=0)
CasBtn.pack(side=LEFT, padx="2m")
CasBtn.menu = Menu(CasBtn)
CasBtn.menu.choices = Menu(CasBtn.menu)
CasBtn.menu.choices.wierdones = Menu(CasBtn.menu.choices)
CasBtn.menu.choices.wierdones.add_command(label='Stockbroker')
CasBtn.menu.choices.wierdones.add_command(label='Quantity Surveyor')
CasBtn.menu.choices.wierdones.add_command(label='Church Warden')
CasBtn.menu.choices.wierdones.add_command(label='BRM')
CasBtn.menu.choices.wierdones.add_command(label='Wooden Leg')
CasBtn.menu.choices.wierdones.add_command(label='Hire Purchase')
CasBtn.menu.choices.wierdones.add_command(label='Dead Crab')
CasBtn.menu.choices.wierdones.add_command(label='Tree Surgeon')
CasBtn.menu.choices.wierdones.add_command(label='Filling Cabinet')
CasBtn.menu.choices.wierdones.add_command(label='Goldfish')
CasBtn.menu.choices.wierdones.add_command(label='Is it a ...')
CasBtn.menu.choices.add_cascade(label='Is it a ...',
menu=CasBtn.menu.choices.wierdones)
CasBtn.menu.add_cascade(label='Scipts', menu=CasBtn.menu.choices)
CasBtn['menu'] = CasBtn.menu
return CasBtn
def makeCheckButtonMenu():
ChkBtn = Menubutton(mBar, text = 'Checkbutton Menus', underline=0)
ChkBtn.pack(side=LEFT, padx='2m')
ChkBtn.menu = Menu(ChkBtn)
ChkBtn.menu.add_checkbutton(label='Doug')
ChkBtn.menu.add_checkbutton(label='Dinsdale')
ChkBtn.menu.add_checkbutton(label='Stig O\'Tracy')
ChkBtn.menu.add_checkbutton(label='Vince')
ChkBtn.menu.add_checkbutton(label='Gloria Pules')
ChkBtn.menu.invoke(ChkBtn.menu.index('Dinsdale'))
ChkBtn['menu'] = ChkBtn.menu
return ChkBtn
def makeRadiobuttonMenu():
RadBtn = Menubutton(mBar, text='Radiobutton Menus', underline=0)
RadBtn.pack(side=LEFT, padx='2m')
RadBtn.menu = Menu(RadBtn)
RadBtn.menu.add_radiobutton(label='metonymy')
RadBtn.menu.add_radiobutton(label='zeugmatists')
RadBtn.menu.add_radiobutton(label='synechdotists')
RadBtn.menu.add_radiobutton(label='axiomists')
RadBtn.menu.add_radiobutton(label='anagogists')
RadBtn.menu.add_radiobutton(label='catachresis')
RadBtn.menu.add_radiobutton(label='periphrastic')
RadBtn.menu.add_radiobutton(label='litotes')
RadBtn.menu.add_radiobutton(label='circumlocutors')
RadBtn['menu'] = RadBtn.menu
return RadBtn
def makeDisabledMenu():
Dummy_button = Menubutton(mBar, text='Disabled Menu', underline=0)
Dummy_button.pack(side=LEFT, padx='2m')
Dummy_button["state"] = DISABLED
return Dummy_button
def makeCommandMenu():
CmdBtn = Menubutton(mBar, text='Button Commands', underline=0)
CmdBtn.pack(side=LEFT, padx="2m")
CmdBtn.menu = Menu(CmdBtn)
CmdBtn.menu.add_command(label="Undo")
CmdBtn.menu.entryconfig(0, state=DISABLED)
CmdBtn.menu.add_command(label='New...', underline=0, command=new_file)
CmdBtn.menu.add_command(label='Open...', underline=0, command=open_file)
CmdBtn.menu.add_command(label='Wild Font', underline=0,
font=('Tempus Sans ITC', 14), command=stub_action)
#CmdBtn.menu.add_command(bitmap="#bitmaps/RotateLeft")
CmdBtn.menu.add('separator')
CmdBtn.menu.add_command(label='Quit', underline=0,
background='white', activebackground='green',
command=CmdBtn.quit)
CmdBtn['menu'] = CmdBtn.menu
return CmdBtn
root = tkinter.Tk()
mBar = Frame(root, relief=RAISED, borderwidth=2)
mBar.pack(fill=X)
CmdBtn = makeCommandMenu()
CasBtn = makeCascadeMenu()
ChkBtn = makeCheckButtonMenu()
RadBtn = makeRadiobuttonMenu()
NoMenu = makeDisabledMenu()
mBar.tk_menuBar(CmdBtn, CasBtn, ChkBtn, RadBtn, NoMenu)
However I receive the following error:
Traceback (most recent call last):
File "Menu.py", line 106, in <module>
mBar.tk_menuBar(CmdBtn, CasBtn, ChkBtn, RadBtn, NoMenu)
AttributeError: 'Frame' object has no attribute 'tk_menuBar'
I read this post:
https://stackoverflow.com/questions/52015321/is-there-any-differences-between-python2-and-python3-about-adding-menu-bar-to-fr
And they say this attribute 'tk_menuBar' has been deprecated from both Python 2 and Python 3. Does anyone have a solution how it should be used in my version of python? (3.6).
mBar = Frame(root, relief=RAISED, borderwidth=2)
after loading the root Tk, you declared mBar as a variable for frame then you try to access it using Object oriented method which i think it won't work
You can still do the following
if name == "main":
root = Tk()
mBar = Frame(root, relief=RAISED, borderwidth=2)
mBar.pack(fill=X)
cmdBtn = makeCommandMenu()
casBtn = makeCascadeMenu()
chkBtn = makeCheckbuttonMenu()
radBtn = makeRadiobuttonMenu()
noMenu = makeDisabledMenu()
menuBar = Menu()
menuBar.add_cascade(label="command", menu=cmdBtn)
menuBar.add_cascade(label="cascade", menu=casBtn)
menuBar.add_cascade(label="check", menu=chkBtn)
menuBar.add_cascade(label="radio", menu=radBtn)
menuBar.add_cascade(label="disable",menu=noMenu)
root.mainloop()

python AttributeError: NoneType has no attribute

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.

Tkinter can't inherit functions from parent class

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

Python Tkinter attribute error entry in random letter typing test

Traceback (most recent call last):
File "C:/Users/Brett/Documents/shellrunpractice", line 83, in <module>
app = simpleapp_tk(None)
File "C:/Users/Brett/Documents/shellrunpractice", line 9, in __init__
self.initialize()
File "C:/Users/Brett/Documents/shellrunpractice", line 22, in initialize
command=self.usertypetest(0),fg="black",bg="green")
File "C:/Users/Brett/Documents/shellrunpractice", line 66, in usertypetest
self.keeptime(num1)
File "C:/Users/Brett/Documents/shellrunpractice", line 44, in keeptime
self.entry.selection_range(0, Tkinter.END)
File "C:\Python27\lib\lib-tk\Tkinter.py", line 1845, in __getattr__
return getattr(self.tk, attr)
AttributeError: entry
Here is the code:
import Tkinter
import random
from time import sleep
class simpleapp_tk(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
def initialize(self):
self.grid()
self.labelVariable = Tkinter.StringVar()
label = Tkinter.Label(self,textvariable=self.labelVariable,anchor="w",fg="blue",bg="gold")
label.grid(column=0,row=0,sticky='EW')
self.labelVariable.set(u"Press button to begin!")
self.button = Tkinter.Button(self,text=u"Start",
command=self.usertypetest(0),fg="black",bg="green")
self.button.grid(column=2,row=0)
self.labelVariable2 = Tkinter.StringVar()
label2 = Tkinter.Label(self,textvariable=self.labelVariable2,anchor="w",fg="blue",bg="gold")
label2.grid(column=1,row=0,sticky='EW')
self.labelVariable2.set(u'Time')
self.entryVariable = Tkinter.StringVar()
self.entry = Tkinter.Entry(self,textvariable=self.entryVariable,fg="black",bg="white")
self.entry.grid(column=0,row=1,columnspan=2,sticky='EW')
self.entryVariable.set(u"")
self.grid_columnconfigure(0,weight=1)
self.grid_rowconfigure(0,weight=1)
self.resizable(True,True)
def keeptime(self,num1):
self.entry.selection_range(0, Tkinter.END)
timer = num1
t = 0
while timer < 1:
self.labelVariable2.set(t)
sleep(.01)
t += .01
def usertype(self):
randletter = random.choice('qwer')
self.labelVariable.set("Press "+randletter)
userinput = self.entryVariable.get
while userinput == '':
pass
if userinput == randletter:
return 'Correct'
else:
return 'Incorrect'
def usertypetest(self,num1):
self.keeptime(num1)
for x in range(20):
result = usertype()
print result
if result == 'Correct':
y = y+5
else:
y = y-2
timer += 1
self.labelVariable.set(str(y)+' is your score')
if __name__ == "__main__":
app = simpleapp_tk(None)
app.title('LoL Practice')
app.geometry("700x50")
app.configure(background='black')
app.mainloop()
I don't know why I am receiving this problem as I am just starting to learn Tkinter and I am not very good yet.
The goal of this program is that when the user clicks start, a timer will start, printing to a label, and they will be shown letters randomly chosen from (Q,W,E,R), which they must type as fast as possible. The program will time them and give them a score based on their errors at the end, and also stop the timer.
I am wondering if you guys could find any other errors in my code that could be causing that, and if so how to do it. I realize my code is very bad, I'm just starting in Tkinter, and I'm not entirely sure how everything works yet.
Any general comments about how I could improve my coding would also be greatly appreciated, as would any comments on how I could write a program to do what I want, as I feel my current method is not practical/functional.
command= expect only function name - without () and parameters.
Using command=self.usertypetest(0) you run self.usertypetest(0)
and its result is assigned to command=.
But self.usertypetest(0) use self.entry which wasn't defined yet.
self.entry is defined after Tkinter.Button(...command=self.usertypetest(0)...)
If you need to assing function with parameters then use lambda
command=lambda:self.usertypetest(0)
And now it works.
EDIT:
Full working version:
(I changed some variable names)
import Tkinter
import random
class simpleapp_tk(Tkinter.Tk):
def __init__(self,parent):
Tkinter.Tk.__init__(self,parent)
self.parent = parent
self.initialize()
self.started = False # True when timer is running
def initialize(self):
self.grid()
self.infoVariable = Tkinter.StringVar()
self.labelInfo = Tkinter.Label(self, textvariable=self.infoVariable, anchor="w", fg="blue", bg="gold")
self.labelInfo.grid(column=0, row=0, sticky='EW')
self.infoVariable.set(u"Press button to begin!")
self.buttonStart = Tkinter.Button(self, text=u"Start", command=self.on_buttonStart, fg="black", bg="green")
self.buttonStart.grid(column=2, row=0)
self.timeVariable = Tkinter.StringVar()
self.labelTime = Tkinter.Label(self, textvariable=self.timeVariable, anchor="w", fg="blue", bg="gold")
self.labelTime.grid(column=1, row=0, sticky='EW')
self.timeVariable.set(u'Time')
self.entryVariable = Tkinter.StringVar()
self.entry = Tkinter.Entry(self, textvariable=self.entryVariable, fg="black", bg="white")
self.entry.grid(column=0, row=1, columnspan=2, sticky='EW')
self.entryVariable.set(u"")
self.entry.bind('<Key>', self.on_key) # event
self.grid_columnconfigure(0,weight=1)
self.grid_rowconfigure(0,weight=1)
self.resizable(True,True)
def on_buttonStart(self):
if not self.started:
# reset values
self.started = True
self.number_of_letters = 20
self.score = 0
self.time = 0.0
# select first letter
self.randletter = random.choice('qwer')
# show first letter and score
self.infoVariable.set('Score:' + str(self.score)+' | Press ' + self.randletter)
# start timer
self.after(100, self.timer)
def on_key(self, event):
if not self.started:
self.entryVariable.set('')
else:
if event.char == self.randletter:
print 'Correct', event.char
self.score += 5
else:
print 'Incorrect', event.char
self.score -= 2
self.number_of_letters -= 1
if self.number_of_letters == 0:
self.started = False
self.entryVariable.set('')
self.infoVariable.set('Score:' + str(self.score))
else:
self.randletter = random.choice('qwer')
self.infoVariable.set('Score:' + str(self.score)+' | Press ' + self.randletter)
def timer(self):
if self.started:
self.time += .1
self.timeVariable.set('Time: ' + str(round(self.time,1)) )
self.after(100, self.timer)
if __name__ == "__main__":
app = simpleapp_tk(None)
app.title('LoL Practice')
app.geometry("700x50")
app.configure(background='black')
app.mainloop()

Categories

Resources