"NameError[Command Name] is not defined" When Using Buttons in Tkinter - python

I'm trying to set up a list of checkbuttons from top to bottom in the GUI and add up the associated "onvalues" for each of the checkbuttons that are on.
My problem now is that for some reason my 'command' attribute in my 'calcbutton' is giving me a "Name 'calc_cost' is not defined" error.
I've added a bunch of imports that you see at the top of the code hoping that would solve the problem, to not much avail.
import tkinter as tk
from tkinter import *
from tkinter import Button
servicelist = ("Oil change","Lube job","Radiator flush","Transmission flush","Inspection","Muffler replacement","Tire rotation")
servicecost = (30,20,40,100,35,200,20)
a = 0
class Window(Frame):
def __init__(self, master=None):
Frame.__init__(self, master)
self.master = master
self.init_window()
def calc_cost(self):
print(a)
def init_window(self):
self.master.title("GUI")
self.pack(fill=BOTH, expand=1)
for i in range(len(servicelist)):
serviceButton = Checkbutton(self, text=servicelist[i], onvalue = servicecost[i], var = a)
serviceButton.place(x=0, rely = i*.1)
calcButton = tk.Button(self, text = "Calculate Cost", fg = "black", bg = "green", command = calc_cost)
calcButton.pack(side = "bottom")
root = Tk()
#size of the window
root.geometry("400x300")
app = Window(root)
root.mainloop()
The checkbuttons pop up and the GUI works for the most part besides the displaying of the 'calcbutton' as well as getting the "NameError: name 'calc_cost' is not defined"

Change command = calc_cost to command = self.calc_cost
self represents the instance of the class. By using the self keyword we can access the attributes and methods of the class in python.
It will give you this output

Related

Tkinter Button class creation

I am trying to create a class, which will help me to optimize/organize creation of another Tkinter buttons. I am aware that an inheritance should have been used. I've been trying to do something like this:
from tkinter import *
window = Tk()
window.title("Button class app")
upper_frame = Frame(window)
upper_frame.pack(fill="both", side=TOP, expand=1)
lower_frame = Frame(window)
lower_frame.pack(fill="both", side=BOTTOM, expand=1)
function1 = None
function2 = None
class Buttons(Button):
def __init__(self, master, text, command):
Button().__init__(self) # or super(). method
self.master=master
self.text=text
self.command=command
self.font=("Comic Sans", 30)
self.fg="#7df9ff",
self.bg="#FFFF00",
self.activeforeground="#7df9ff",
self.activebackground="#FFFF00",
self.state=ACTIVE,
self.compound='bottom',
button1 = Buttons(upper_frame, "Some text 1", function1)
button1.pack(fill="x")
button2 = Buttons(lower_frame, "Some text 2", function2)
button2.pack(fill="x")
I've been trying to use super() method instead of Button().__ init __(), but I am not sure what arguments should I pass on to/what should I really inherit. Using super().
method gives me error: 'Buttons' object has no attribute 'tk'.
Somehow, also with Button(). __ init __ I could also get access to i.e.: self["text"]=text, but not with self.text=text as usual (why?)
I've been also trying to make a class for main Tkinter window, and then for frames - to make inheritance for a Tkinter Button Class object - but I think this is not the way it should work - I think I should make an inheritance from predefined Tkinter Button/tk.Button class.
I will be very grateful for any help or explanations.
In other GUIs you could use self.text but tkinter uses
self['text'] = text
self.config(text=text)
And the same with other values (maybe except master)
It allow also
self.config(text=text, command=command)
self.config({"text":text, "command":command})
setting = {'text': 'other', 'bg': 'red'}
self.config(setting)
setting = {'text': 'other', 'bg': 'red'}
self.config(**setting) # with `**` to unpack dictionary
Full working code.
import * is not preferred - using import tkinter as tk I can create class with name Button (without s) and use three different classes at the same time: tk.Button, ttk.Button and my Button.
In __init__ I use **kwargs so I can send other parameters to class.
import tkinter as tk # PEP8: `import *` is not preferred
# --- classes --- # PEP8: all classes after imports
class Button(tk.Button):
def __init__(self, master, text, command, **kwargs):
super().__init__(master, text=text, command=command)
#self.master = master
#self['text'] = text # PEP8: spaces around `=`
#self['command'] = command
self['font'] = ("Comic Sans", 30)
self['fg'] = "#7df9ff"
self['bg'] = "#FFFF00"
self['activeforeground'] = "#7df9ff"
self['activebackground'] = "#FFFF00"
self['state'] = 'active'
self['compound'] = 'bottom'
self.config(**kwargs)
# --- functions --- # PEP8: all functions after classes (before main code)
def function1():
print('function1')
def function2():
print('function2')
# --- main ---
window = tk.Tk()
window.title("Button class app")
upper_frame = tk.Frame(window)
upper_frame.pack(fill="both", side=TOP, expand=1)
lower_frame = tk.Frame(window)
lower_frame.pack(fill="both", side=BOTTOM, expand=1)
button1 = Button(upper_frame, "Some text 1", function1, bg='red', activebackground='blue')
button1.pack(fill="x")
button2 = Button(lower_frame, "Some text 2", function2, bg='green', activebackground='blue')
button2.pack(fill="x")
window.mainloop()
PEP 8 -- Style Guide for Python Code

tkinter: Why am I getting a small window plus my main window and gridding is off? __init__ problem?

Creates two windows and gridding is not correct. Some additional comments in the code initiation.
I have used this approach, without the super init with no problem, many times.
Advice appreciated.
Thanks
# timhockswender#gmail.com
import tkinter as tk
from tkinter import ttk
class constants_page(tk.Frame):
def __init__(self):
super(constants_page, self).__init__() # from stackoverflow
# if not used error = 'constants_page' object has no attribute 'tk'
# if used, another tiny window is opened
# in addtion to the constants_page
self.constants_page = tk.Tk()
self.constants_page.geometry("1000x500") #width*Length
self.constants_page.title("Owen's Unit Conversion App")
self.constants_page.configure(background='light blue')
self.CreateWidgets()
def CreateWidgets(self):
self.value_label = ttk.Label(self.constants_page,text="Value----->" , width =10 )
self.value_label.grid(row=0, column=1, columnspan=1, sticky='nse')
# Problem: not gridding properly
self.title_label = ttk.Label(self.constants_page, text="Important Physical Constants",
anchor=tk.CENTER, font=("Arial",20)).grid(row=2, columnspan=2)
for r in range(2):
self.constants_page.rowconfigure(r, weight=1, uniform='row')
for c in range(2):
self.constants_page.columnconfigure(c, weight=1 )
def Show_Page():
# Create the entire GUI program
program = constants_page()
program.mainloop()
if __name__ == "__main__":
Show_Page()
The super call expects you to provide a root window (an instance of tk.Tk()). If you don't provide one it defaults to the first root window opened, and if none has been opened yet then it helpfully opens one for you. A few lines later you open a second one yourself.
The easy fix is to remove the self.constants_page = tk.Tk() line. The proper fix is to make the Tk() instance outside of the class and pass it in. This allows you to use the Frame class itself to lay out widgets (use self instead of self.constants_page). Try this:
import tkinter as tk
from tkinter import ttk
class constants_page(tk.Frame):
def __init__(self, master=None, **kwargs):
super().__init__(master, **kwargs)
master.geometry("1000x500") #width*Length
master.title("Owen's Unit Conversion App")
self.configure(background='light blue')
self.CreateWidgets()
def CreateWidgets(self):
self.value_label = ttk.Label(self,text="Value----->" , width =10 )
self.value_label.grid(row=0, column=1, columnspan=1, sticky='nse')
self.title_label = ttk.Label(self, text="Important Physical Constants",
anchor=tk.CENTER, font=("Arial",20)).grid(row=2, columnspan=2)
for r in range(2):
self.rowconfigure(r, weight=1, uniform='row')
for c in range(2):
self.columnconfigure(c, weight=1 )
def Show_Page():
# Create the entire GUI program
program = tk.Tk()
win = constants_page(program)
win.pack()
program.mainloop()
if __name__ == "__main__":
Show_Page()

unable to set default value for tkinter checkbox

I am trying to create checkbox with default value True,but it's not working, I tried plenty of the answers but didn't work
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Test v1")
self.geometry("400x250")
self.build_init()
def build_init(self):
#CheckVar = tk.BooleanVar(self,)
CheckVar = tk.IntVar(value=1)
checkbutton = tk.Checkbutton(self, text = "Test", variable = CheckVar,onvalue=1, offvalue=0)
#checkbutton.select()
checkbutton.place(x=20,y=80)
App().mainloop()
I coouln't find much on it in the documentaion other than select which didn't work, Also on this question Tkinter: is there a way to check checkboxes by default?
import tkinter as tk
class App(tk.Tk):
def __init__(self):
super().__init__()
self.title("Test v1")
self.geometry("400x250")
self.build_init()
def build_init(self):
#CheckVar = tk.BooleanVar(self,)
self.CheckVar = tk.IntVar(value=1)
self.checkbutton = tk.Checkbutton(self, text = "Test", variable = self.CheckVar,onvalue=1, offvalue=0)
#checkbutton.select()
self.checkbutton.place(x=20,y=80)
App().mainloop()

String Variable not setting initial value

class Lay():
def __init__(self):
root=Tk()
root.configure(background="black")
var=StringVar()
var.set("OVERVIEW")
Label(root,textvariable=var).grid(row=1,column=1,sticky=W+E+N+S)
Entry(root, textvariable = var).place(rely=1.0,relx=1.0,x=0,y=0,anchor=SE)
root.mainloop()
Hello, when i run this the initial value of the string variable does not appear, but when i type into the entry box, the text i type appears in the label. I'm not quite sure why this occurs, but i get an empty label to begin with, with the entry box. Thank you for any help.
Although, I couldn't reproduce the problem, I refactored your code to initialize tkinter widgets through a class(inspired by the snippet in the docs) and also increased the window size so that the widgets are clearly viewed. If there is anything else in your code that is calling multiple windows as #jasonharper suggested, you should share that.
import tkinter as tk
class Lay(tk.Tk):
def __init__(self, master=None):
super().__init__(master)
self.master = master
self.var=tk.StringVar()
self.var.set("OVERVIEW")
self.Widgets()
def Widgets(self):
self.displaylbl = tk.Label(self,textvariable=self.var)
self.displaylbl.grid(row=2,column=1,sticky=tk.W+tk.E+tk.N+tk.S)
self.entry = tk.Entry(self, textvariable = self.var)
self.entry.place(rely=1.0,relx=1.0,x=0,y=0,anchor=tk.SE)
app = Lay()
app.geometry("200x200")
app.mainloop()
Output:

Python Tkinter, how to disable a button in a class?

I have seen many explanations of how to turn an enabled button disabled but not when classes are involved. The error here is in the line 'button_1.config...' and the error message is that button_1 is not defined. I think this is because it is in a different method but im not sure how to disable a button from a different method. any help is appreciated.
from tkinter import *
class menu:
def __init__(self, master):
self.master = master
button_1 = Button(self.master, text = 'test', command = self.correct).pack()
def correct(self):
button_1.config(state = DISABLED)
def window():
root = Tk()
menu(root)
root.mainloop()
if __name__ == '__main__':
window()
The button needs to be an instance variable, if you're accessing it between methods in the class. Just add self. in front of it. It's also going to need to be packed on a separate line, otherwise the instance variable self.button_1 will return None:
class menu:
def __init__(self, master):
self.master = master
self.button_1 = Button(self.master, text = 'test', command = self.correct)
self.button_1.pack()
def correct(self):
self.button_1.config(state = DISABLED)

Categories

Resources