I am trying to create a GUI in Python for a class assignment called 'Chocolate Vending Machine'. Students are required to use Python's Tkinter. We list a couple of chocolate brands such as Snickers, Twix and Mars and put a price tag on each of them. The user goes through these steps:
Please refer to the code below. How can I abstract the following lines of code so that it still works, but limits the number of lines? Note that I am not pasting the whole code of the application as it is just too many lines of code. So here's a snippet to narrow things down:
#----------------------Chocolate---------------------
Twix=DoubleVar()
Snickers=DoubleVar()
MarsBar=DoubleVar()
Godiva=DoubleVar()
lblTwix = Label(f1, font=('arial', 16, 'bold'), text='Twix',bg = 'powder blue',bd=19,anchor='w')
lblTwix.grid(row=2,column=0)
txtTwix = Entry(f1,font=('arial',16,'bold'),textvariable=Twix,bd=10,insertwidth=4,
bg='powder blue',justify='right')
txtTwix.grid(row=2,column=1)
lblSnickers = Label(f1, font=('arial', 16, 'bold'), text='Snickers', bg = 'powder blue',bd=19,anchor='w')
lblSnickers.grid(row=4,column=0)
txtSnickers = Entry(f1,font=('arial',16,'bold'),textvariable=Snickers,bd=10,insertwidth=4,
bg='powder blue',justify='right')
txtSnickers.grid(row=4,column=1)
lblMarsBar = Label(f1, font=('arial', 16, 'bold'), text='Mars Bar', bg = 'powder blue',bd=19,anchor='w')
lblMarsBar.grid(row=6,column=0)
txtMarsBar = Entry(f1,font=('arial',16,'bold'),textvariable=MarsBar,bd=10,insertwidth=4,
bg='powder blue',justify='right')
txtMarsBar.grid(row=6,column=1)
lblGodiva = Label(f1,font=('arial',16,'bold'), text="Godiva", bg = 'powder blue',bd=19, anchor='w')
lblGodiva.grid(row=9, column=0)
txtGodiva = Entry(f1,font=('arial',16,'bold'),textvariable=Godiva,bd=10,insertwidth=4,
bg='powder blue',justify='right')
txtGodiva.grid(row=9,column=1)
#==================================Balance, Cost=======================================
InitialBalance=DoubleVar()
Cost=StringVar()
FinalBalance=StringVar()
lblInitialBalance = Label(f1,font=('arial',20,'bold'), text="Initial Balance", bg = 'powder blue', bd=29, anchor='w')
lblInitialBalance.grid(row=2, column=10)
txtInitialBalance=Entry(f1,font=('arial',20,'bold'), textvariable=InitialBalance, bd=28, insertwidth=4,
bg='steel blue', justify='right')
txtInitialBalance.grid(row=2, column=12)
lblCost = Label(f1,font=('arial',20,'bold'), text="Total Cost", bg = 'powder blue',bd=29, anchor='w')
lblCost.grid(row=4, column=10)
txtCost=Entry(f1,font=('arial',20,'bold'), textvariable=Cost, bd=28, insertwidth=4,
bg='powder blue', justify='right')
txtCost.grid(row=4, column=12)
lblFinalBalance = Label(f1,font=('arial',20,'bold'), text="Final Balance", bg = 'powder blue',bd=29, anchor='w')
lblFinalBalance.grid(row=6, column=10)
txtFinalBalance=Entry(f1,font=('arial',20,'bold'), textvariable=FinalBalance, bd=28, insertwidth=4,
bg='powder blue', justify='right')
txtFinalBalance.grid(row=6, column=12)
REVISED CODE:
Twix=DoubleVar()
Snickers=DoubleVar()
MarsBar=DoubleVar()
Godiva=DoubleVar()
def make_entry(frame, text, variable, row, col1, col2):
label = Label(frame, font=('arial',20,'bold'), text=text, textvariable = variable, bg = 'powder blue', bd=19, anchor='w')
label.grid(row=row, column=col1)
entry=Entry(f1,font=('arial',20,'bold'), textvariable=variable, bd=28, insertwidth=4,
bg='steel blue', justify='right')
entry.grid(row=row, column=col2)
return label, entry
make_entry(f1, "Twix", Twix, 2, 0, 1)
make_entry(f1, "Snickers", Snickers, 4, 0, 1)
make_entry(f1, "MarsBar", MarsBar, 6, 0, 1)
make_entry(f1, "Godiva", Godiva, 9, 0, 1)
And here is a link to the full, non-abstracted code:
https://docs.google.com/document/d/1tMJxmFAMWyc6qhTFnhoedQmj49Qkf56rJxhxB8Z3fSM/edit?usp=sharing
As you can see, every line of code pasted above has to do with the styling of the buttons and the boxes that the user can input necessary information for the program to do its job. With all of that said, I reiterate the question:
what is the most efficient way to condense all of this code into fewer lines and still make it work? How could I use classes and def statements to rewrite the code in a more efficient fashion?
I have attempted to abstract the code above, but it did not work. Any help is appreciated.
You can define a function for creating the Label
and Entry
with the given parameters:
def make_entry(frame, text, variable, row, col1, col2):
font = ('arial',16,'bold')
label = Label(frame, font=font, text=text, bg='powder blue', bd=19, anchor='w')
label.grid(row=row, column=col1)
entry = Entry(frame, font=font, textvariable=variable, bg='powder blue', bd=10, insertwidth=4, justify='right')
entry.grid(row=row, column=col2)
Then, just call that function for your different candies.
make_entry(f1, "Twix", Twix, 2, 0, 1)
make_entry(f1, "Snickers", Snickers, 4, 0, 1)
...
You might also have the function return label, entry
if you need those later on, but it seems like the variables are enough.
The parameters in the second group are a bit different: Larger font size, thicker borders, different shades of blue. You could either make those additional parameters to the function, or create a second function for those buttons similar to the first.
Alternatively, you could also just create two loops instead of defining a function. Particularly if the differences between the first and the second group of entries are more significant this may be simpler than using two very similar functions, or one function with very many parameters.
candies = [("Twix", Twix), ("Snickers", Snickers),
("Mars Bar", MarsBar), ("Godiva", Godiva)]
font = ('arial',16,'bold')
for i, (name, var) in enumerate(candies, start=1):
label = Label(f1, font=font, text=name, bg='powder blue', bd=19, anchor='w')
label.grid(row=2*i, column=0)
entry = Entry(f1, font=font, textvariable=var, bg='powder blue', bd=10, insertwidth=4, justify='right')
entry.grid(row=2*i, column=1)
Also, unrelated to the actual problem, DoubleVar
does not seem to be a sensible choice for a countable quantity like chocolate bars. Are your users supposed to be able to buy 3.14 Mars bars? Instead, I'd suggest using IntVar
.
About your "revised code": There are two problems: First, the use of the function make_entry(f1, ...)
should not be inside the function, but on the root level (no indentation). Second, you accidentally added textvariable=variable
to the Label
constructor, where it does not belong; only to Entry
.