My Button Functions Are Not Working in my Python code - python

Good Day,
I'm designing a simple eatery Gui in Python with the Tkinter library but my "Reset" and "Calculate Price" buttons don't work as they should. Please what could the problem be?
from tkinter import *
class Application (Frame):
def __init__(self,anjie):
super(Application,self).__init__(anjie)
#getting the init() function in frame,the superclass
#super is a function that takes two parameters: the name of your subclass i.e. Application and self
self.grid() #allows grid function to work
self.toppings=["sausage","pepperoni","chicken","mushroom","black olive","green pepper","red pepper","onion"]
self.prices={"medium":9.99, "large":12.99, "x-large":14.99, "mid-topping":1.0, "large-topping":1.4, "xl-topping":1.8}
self.checkbox=list(self.toppings)
self.checkboxVar=list(self.toppings)
self.create_widgets()
def create_widgets(self):
menubar=Menu(self)
filemenu=Menu(menubar)
menubar.add_cascade(label="File", menu=filemenu)
menubar.add_cascade(label="Quit",command=window.quit)
filemenu.add_command(label="Submit",command=self.process)
self.label1=Label(self,text="Select size: ")
self.label1.grid(row=0,column=0,sticky=W)
self.size=StringVar() #similar to name in html, groups similar elements together with variable self.size
print(StringVar())
self.radio1=Radiobutton(self,text="Medium",variable=self.size,value="Medium")
self.radio1.grid(row=1,column=0,sticky=W)
self.radio1.select() #makes radio1 the default selected radio button
self.radio2=Radiobutton(self,text="Large",variable=self.size,value="Large")
self.radio2.grid(row=1,column=1,sticky=W)
self.radio2.select()
self.radio3=Radiobutton(self,text="Extra Large",variable=self.size,value="X-Large")
self.radio3.grid(row=1,column=2,sticky=W)
self.radio3.select()
self.label2=Label(self,text="Select size: ")
self.label2.grid(row=2,column=0,sticky=W)
line=2#last row number
for i in range(len(self.toppings)):
line+=1
self.checkboxVar[i]=BooleanVar() #default value added is false
self.checkboxVar[i]=Checkbutton(self,text=self.toppings[i], variable=self.checkboxVar[i])
self.checkboxVar[i].grid(row=line,column=0,sticky=W)
line+=1
self.button1=Button(self,text="Reset",command=self.reset)
self.button1.grid(row=line,column=0,sticky=E)
self.button2=Button(self,text="Calculate Price",command=self.calculate)
self.button2.grid(row=line,column=2)
line+=1
self.label3=Label(self,text="")
self.label3.grid(row=line,column=0)
line+=1
self.label4=Label(self,text="Total: ")
self.label4.grid(row=line,column=0,sticky=E)
self.result=Entry(self,width=10)
self.result.grid(row=line,column=1,sticky=W)
window.config(menu=menubar)
def process(self):
print("This is the process to submit: ")
def reset(self):
self.radio1.select()
for i in range(len(self.toppings)):
self.checkbox[i].deselect()
self.result.delete(0,END)
def calculate(self):
self.totalToppings=0
for i in range(len(self.toppings)):
if self.checkboxVar[i].get():
self.totalToppings+=1
if self.size.get()=="Medium":
self.price=self.prices["medium"]+(self.totalToppings * self.prices["mid-topping"])
if self.size.get()=="Large":
self.price=self.prices["large"]+(self.totalToppings*self.prices["large-topping"])
if self.size.get()=="X-Large":
self.price=self.prices["x-large"]+(self.totalToppings*self.prices["xl-topping"])
str_price="{.2f}".format(self.price)
self.result.delete(0,END)
self.result.insert(END,str_price)
window=Tk()
window.title("Anjie\'s Pizza")
window.geometry("800x500") #WIDTH BY HEIGHT
app=Application(window)
app.mainloop()
I would appreciate any help regarding this. I did this with the Python tkinter library and my problem is that no result appears in the total entry.

There are few issues in your code:
Call .select() on all radio buttons, should only call self.radio1.select() initially
Used self.checkboxVar[i] instead of self.checkbox[i]
def create_widgets(self):
...
#self.radio2.select() # should not call
...
#self.radio3.select() # should not call
...
line=2#last row number
for i in range(len(self.toppings)):
line+=1
self.checkboxVar[i]=BooleanVar() #default value added is false
### should use self.checkbox[i]=... instead of self.checkboxVar[i]=...
self.checkbox[i]=Checkbutton(self,text=self.toppings[i], variable=self.checkboxVar[i])
self.checkbox[i].grid(row=line,column=0,sticky=W)
...
Used invalid float format {.2f}, should be {:.2f} instead:
def calculate(self):
...
str_price="{:.2f}".format(self.price)
...

Related

How do I use tklib widgets in tkinter?

I was looking for an IP address entry widget for tkinter for use with python3.7 and came across ipentry in the tklib.
https://core.tcl-lang.org/tklib/doc/trunk/embedded/www/tklib/files/modules/ipentry/ipentry.html#section2
This is not a terribly complicated need to 'recreate the wheel' for and there are several examples on stackoverflow for IP entry boxes but I'd really like to understand how to use the modules and widgets in the tklib with tkinter. Documentation or examples appear to be few and far between. Here's how far I've gotten:
First of all, I have to tell Python that this widget exists.
import tkinter as tk
root = tk.Tk()
root.tk.call(‘package’,’require’,’ipentry’)
Then I created a class for the widget.
class iPentry(tk.Widget):
def __init__(self, master):
tk.Widget.__init__(self, master, '::ipentry::ipentry’)
Then I create an instance of it and pack it in my window.
enterIp = iPentry(root)
enterIp.pack()
So far so good. I get a window with a familiar looking input box for an IPV4 address.
The problem is that I haven't figured out how to use the get or complete or insert widget commands. When I try to get from the enterIp widget that I created, I get an error.
myip = enterIp.get()
Traceback (most recent call last):
File "<stdin>", line 1, in <module>
AttributeError: 'iPentry' object has no attribute 'get'
I suspect that I'm missing some syntax concepts. Any suggestions for how to do this?
You need to define get() function in your wrapper class iPentry:
def get(self):
return self.tk.call(self._w, 'get')
Actually you need to define every functions that ipentry provides like above if you want to call them.
Thanks to acw1668 I was able to work through some bone headed mistakes and figure this out a bit. Here is some sample code for someone else who might like to work with these in Python. They are pretty limited and I found a few things that didn't work even though they are documented on the lib page. But they might be useful for some situations. The rdial in particular was surprising because it is visually a "thumbwheel" rather than a typical round dial. I have included a screenshot of what some of these look like in Macos.
This code displays an iPentry with a label below that will populate with the address when you press enter. Then there is a bank of 3 sliders whose values will show in a label below. Then an rdial whose value shows in a label below and finally a "voltmeter" that bounces around based on a random number. Enjoy.
# This Python file uses the following encoding: utf-8
# Python 3.7 and Tk version 8.6
import sys
import tkinter as tk
import random
class iPentry(tk.Widget):
def __init__(self, master):
tk.Widget.__init__(self, master, '::ipentry::ipentry')
def get(self):
return self.tk.call(self._w, 'get')
def complete(self):
return self.tk.call(self._w, 'complete')
class CWslider(tk.Widget):
def __init__(self, master, placeholder):
tk.Widget.__init__(self, master, '::controlwidget::slider',
{'variable':placeholder, 'from_':0, 'to':20, 'number':3,
'width':55, 'background':'yellow'})
def get(self):
getvalue = self.tk.call(self._w, 'get')
getvalue = [int(x) for x in getvalue]
return getvalue
def set(self, value):
self.tk.call(self._w, 'set', value)
def complete(self):
return self.tk.call(self._w, 'complete')
class CWrdial(tk.Widget):
def __init__(self, master):
tk.Widget.__init__(self, master, '::controlwidget::rdial',
{'width':50, 'orient':'vertical', 'height':100, 'background':'green'})
def get(self):
return self.tk.call(self._w, 'get')
def complete(self):
return self.tk.call(self._w, 'complete')
class CWvoltmeter(tk.Widget):
def __init__(self, master, variable):
tk.Widget.__init__(self, master, '::controlwidget::voltmeter',
{'min':0, 'max':100, 'variable':variable})
def getIP(event):
myip = enterIp.get()
labelvar.set(myip)
print(f"myip is {myip}")
def updating(master, myValuesvar, myvoltvar, interval):
#we can't get value from placeholder because slider corrupts the IntVar?
slidervalues = slider.get() #so we use the get method
myValuesvar.set(slidervalues)
mydialvalue.set(mydial.get())
myvoltvar.set( random.randrange(0, 100, 1))
root.after(interval, updating, root, myValuesvar, myvoltvar, interval)
root = tk.Tk()
root.geometry("300x550+280+0")
root.tk.call('package','require','ipentry')
root.tk.call('package','require','controlwidget')
enterIp = iPentry(root)
enterIp.pack()
labelIP = tk.Label(root, text="Show The IP")
labelIP.pack()
labelvar = tk.StringVar()
label2 = tk.Label(root, textvariable=labelvar)
label2.pack()
root.bind('<Return>', getIP)
myvalues = [5,15,3]
myValuesvar = tk.IntVar()
placeholder = tk.IntVar() #necessary for slider to change values
slider = CWslider(root, placeholder)
slider.pack()
slider.set(myvalues)
labelSlider = tk.Label(root, textvariable=myValuesvar)
labelSlider.pack()
mydialvalue = tk.StringVar()
mydial = CWrdial(root)
mydial.pack()
labeldial = tk.Label(root, textvariable=mydialvalue)
labeldial.pack()
myvoltvar = tk.IntVar()
myvolt = CWvoltmeter(root, myvoltvar)
myvolt.pack()
interval = 300 #milliseconds for GUI
updating(root, myValuesvar, myvoltvar, interval)
root.mainloop()
sys.exit()

Issue retrieving values from objects created by button function

I'm working on a small project and I'm having issues retrieving the values stored in combo boxes. The program has a "plus" button that creates additional boxes beneath the existing ones. They are created by calling a "create" function that makes a new instance of the ComboBox class, where the box is created and put onto the screen. A separate "submit" function is then supposed to loop through and retrieve all of the box values and store them in a list. My main flaw is that I used data in the variable names, but I have no clue how else to do this in this scenario. Does anyone have an alternative solution?
(there are some off screen variables that are show used here as parameters, but there are definitely not the source of the issue)
class ComboBox:
def __init__(self, master, counter, fields):
self.master = master
self.counter = counter
self.fields = fields
self.field_box = ttk.Combobox(width=20)
self.field_box["values"] = fields
self.field_box.grid(row=counter + 1, column=0, pady=5)
def get_value(self):
value = self.field_box.get()
return value
def create():
global entry_counter
name = "loop"+str(entry_counter-1)
name = ComboBox(window, entry_counter, fields)
values.append(name.get_value())
entry_counter += 1
def submit():
for i in range(1, entry_counter):
name = "loop" + str(entry_counter-1)
values.append(name.get_value())
For example, if I created 2 boxes and selected the options "test1" and "test2" I would want the my values list to contain ["test1, "test2"]
Not sure I understand the question right, but I guess you are asking about how to loop throw all instances of ComboBox. You can just create an global array, append new instance into it in create() method:
comboboxes = []
def create():
...
comboboxes.append(new_instance)
def submit():
for combobox in comboboxes:
...
You're on the right track with .get(). I believe your solution is that your get_value function also needs an event parameter:
def get_value(self, event):
value = self.field_box.get()
return value
See the following:
Getting the selected value from combobox in Tkinter
Retrieving and using a tkinter combobox selection

Using Entry and updating an entry entered, as the user continues to change the values (using trace method) in TKinter

I am learning Python and I am starting to learn how to use the TKinter GUI. I am making a small interface that does some simple statistical analysis like STDEV, T-tests, etc. I have this method in a class which basically gets the data to work with.
I want the user to be able enter as many data entries as they want (I mean as long as the computer can handle of course). The problem I am having is -- I think when I use the method .get() on an Entry, None is returned?
I am also using method .trace() of DoubleVar() to trace when the values of the entries are updated using the method shown here:
Python Tkinter update when entry is changed
I thought it made sense but it's not working for me. Whenever I change a box in my TK interface, all the other boxes get changed, but the values used to calculate standard deviation are not the numbers that are being shown on the Entry boxes (which are all the same anyways).
Here is the code:
class StandardDeviation:
"""
Runs standard deivation calculations.
"""
def __init__(self) -> None:
"""
Initializes an instance of the functions!
"""
self.stdev_pop = Button(top_frame,
text="Calculate the population "
"standard deviation of the data set")
self.stdev_pop.bind("<Button-1>", self.show_result_population)
self.stdev_pop.pack()
stdev_samp = Button(top_frame,
text="Calculate the sample "
"standard deviation of the data set")
stdev_samp.bind("<Button-1>", self.show_result_sample)
stdev_samp.pack()
self.data = []
self.enter_data = Button(top_frame, text="Enter data")
self.enter_data.bind("<Button-1>", self.pack_add_entry_button)
self.add_entry = Button(top_frame, text="Add data entry",
command=self.add_new_entry)
self.enter_data.pack()
self.all_entries = {}
self.tracer = DoubleVar()
self.tracer.trace("w", self.update)
def pack_add_entry_button(self, *args) -> None:
"""
Pack the add_entry button.
"""
self.add_entry.pack()
def update(self, *args) -> None:
"""
Update the values of the entries.
"""
global update_in_progress
if update_in_progress:
return
update_in_progress = True
data = [str(self.all_entries[item]) for item in self.all_entries]
self.data = [int(item) for item in data if item.isnumeric()]
update_in_progress = False
def add_new_entry(self):
"""
Add a new entry.
"""
new_entry = Entry(root, textvariable=self.tracer)
new_entry.pack()
new_entry_data = new_entry.get()
self.all_entries[new_entry] = new_entry_data
I'm not sure where I'm wrong here if anyone could help me I'd really appreciate it. Thank you!
There is no way to run the code you posted as the indentation is off and some of the buttons call functions that don't exist so this is a standard trace program that shows how to use the tkinter variable associated with the trace, a StringVar in ths case, to get the contents.
import tkinter
def text_changed(*args):
print(tk_name.get())
top = tkinter.Tk()
tk_name=tkinter.StringVar()
tk_name.set("nothing")
tk_name.trace("w", text_changed)
tkinter.Label(top, textvariable=tk_name).grid(row=0, column=1)
entry_1 = tkinter.Entry(top, textvariable=tk_name)
entry_1.grid(row=1, column=1, sticky="W")
entry_1.focus_set()
top.mainloop()

tkinter new class can't use .get()/float()

I have defined a new Entry subclass: NewEntry, but it can't get the numbers which are put in it. How can I fix this?
When I click the button, the error message is showed:
ValueError: could not convert string to float:
from Tkinter import *
root = Tk()
class NewEntry(Entry):
def __init__(self,parent,cusdef='1'): #Initiation default number is '1'
Entry.__init__(self,parent)
self.cusdef = cusdef
v=StringVar()
v.set(self.cusdef)
self = Entry(self,textvariable=v)
self.pack()
return
def GetNum():
a=e.get()
print float(a)
return
e = NewEntry(root)
e.pack(fill='x')
button = Button(root,command=GetNum)
button.pack(fill='x')
root.mainloop()
You seem to be trying to initialize your Entry subclass here:
self = Entry(self,textvariable=v)
self.pack()
But instead, you're merely overwriting the variable called self and creating a new Entry which gets discarded.
Instead you need to do the Entry.__init__ call once, with the correct arguments:
class NewEntry(Entry):
def __init__(self,parent,cusdef='1'):
self.cusdef = cusdef
v=StringVar()
v.set(self.cusdef)
Entry.__init__(self,parent, textvariable=v)
self.pack()
return

button command option in tkinter

In the little GUI app below. When I use button's command option to call a function. It doesn't work like this: self.update() rather it works like this: self.update. Why so? Is is some special way that command option of a button works? I think a method or a function should be called with those braces (), unless it's a property:
i.e.
#name.setter:
def setter(self, name):
self.name = name
#main
object.name = "New_obj"
Note: The above is just a template so you might get my point. I didn't write the complete valid code. Including class and everything.
from tkinter import *
class MuchMore(Frame):
def __init__(self, master):
super(MuchMore,self).__init__(master)
self.count =0
self.grid()
self.widgets()
def widgets(self):
self.bttn1 = Button(self, text = "OK")
self.bttn1.configure(text = "Total clicks: 0")
self.bttn1["command"] = self.update # This is what I am taking about
self.bttn1.grid()
def update(self):
self.count += 1
self.bttn1["text"] = "Total clicks" + str(self.count)
#main
root = Tk()
root.title("Much More")
root.geometry("324x454")
app = MuchMore(root)
It is a high order function, meaning you are referencing a function as an object. You are not calling the function and assigning the command to the return value of the function. See here for more information.
The command parameter takes a reference to a function -- ie: the name of the function. If you add parenthesis, you're asking python to execute the function and give the result of the function to the command parameter.

Categories

Resources