0

Here, I am trying to create a GUI calculator in Python for a class assignment called 'Chocolate Machine'.

But I've run into a problem; the code below is not printing the buttons in the GUI! To see what I'm talking about, please look at the code below the commented line:

#CODE THAT IS NOT PRINTING THE BUTTON IS BELOW

It's basically buttons 7, 8, 9, and the addition button, which is supposed to appear on the top row of every simple calculator.

Could someone assist and help me understand why this is not working? I've tried to use pack statements but they don't work either.

The tutorial I have been using is by DJ Oamen on YouTube. Two images are attached, the one of the working GUI by DJ Oamen, and the one that does not work by me.

Working GUI Calculator by DJ Oamen:

Working GUI Calculator by DJ Oamen

Unworking GUI Calculator (no buttons):

Unworking GUI Calculator (no buttons)

from tkinter import *
import random
import time;

root = Tk()
root.geometry("1600x800+0+0")
root.title("Cameron's Chocolate Machine")

text_Input = StringVar()
operator = ""

Tops = Frame(root, width=1600, height=50, bg="powder 
blue",relief=SUNKEN)
Tops.pack(side=TOP)

f1 = Frame(root, width=800, height=700, bg="powder blue",relief=SUNKEN)
f1.pack(side=LEFT)

f2 = Frame(root, width=300, height=700, bg="powder blue",relief=SUNKEN)
f2.pack(side=RIGHT)

localtime = time.asctime(time.localtime(time.time()))
lblInfo = Label(Tops, font=('simplifica', 50, 'bold'), text="Cameron's Chocolate Machine",
    fg="Steel Blue",bd=10, anchor='w')
lblInfo.grid(row=0,column=0)

lblInfo = Label(Tops, font=('simplifica', 20), text=localtime,fg="Steel Blue",
    bd=10,anchor='w')
lblInfo.grid(row=1,column=0)

def btnClick(numbers):
    global operator
    operator= operator + str(numbers)
    text_Input.set(operator)

txtDisplay = Entry(f2, font=('arial',20,'bold'),textvariable=text_Input, bd=30, 
    insertwidth=4,bg='powder blue', justify='right')
txtDisplay.grid(columnspan=4)

#CODE THAT IS NOT PRINTING THE BUTTON IS BELOW
btn7=Button(f2,padx=16,pady=16,bd=8,fg="black",font=('arial', 20, 
    'bold'),text="7",bg="powder blue",command=lambda:btnClick(7).grid(row=2,column=0))

btn8=Button(f2,padx=16,pady=16,bd=8,fg="black",font=('arial', 20, 'bold'),
    text="8",bg="powder blue",command=lambda: btnClick(8).grid(row=2,column=1))

btn9=Button(f2,padx=16,pady=16,bd=8,fg="black",font=('arial', 20, 'bold'),
    text="9",bg="powder blue",command=lambda: btnClick(9).grid(row=2,column=2))

Addition=Button(f2,padx=16,pady=16,bd=8,fg="black",font=('arial', 20, 'bold'),
    text="9",bg="powder blue",command=lambda: btnClick("+").grid(row=2,column=3))

root.mainloop()
3
  • Do they maybe have the same colour? Commented Feb 20, 2018 at 9:24
  • Check the command for the. Commented Feb 20, 2018 at 9:28
  • Please lose all redundant parts in order to have a clear question with a minimal reproducible example. Commented Feb 21, 2018 at 17:59

5 Answers 5

1

For each button, you need to set a grid for each one to display them. For example:

btn7.grid(row=0, column=0)
Sign up to request clarification or add additional context in comments.

Comments

0

The calculator alone working

enter image description here

from tkinter import *


def iCalc(source, side):
    storeObj = Frame(source, borderwidth=4, bd=4, bg="black")
    storeObj.pack(side=side, expand=YES, fill=BOTH)
    return storeObj


def button(source, side, text, command=None):
    storeObj = Button(source, text=text, command=command)
    storeObj.pack(side=side, expand=YES, fill=BOTH)
    return storeObj


class app(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.option_add("*Font", "arial 20 bold")
        self.pack(expand=YES, fill=BOTH)
        self.master.title("Calculator")

        display = StringVar()
        # relief can be FLAT or RIDGE or RAISED or SUNKEN GROOVE
        Entry(self, relief=RIDGE, textvariable=display, justify='right', bd=30, bg='darkgray').pack(side=TOP, expand=YES, fill=BOTH)

        for clearBut in (["CE"], ["C"]):
            erase = iCalc(self, TOP)
            for ichar in clearBut:
                button(erase, LEFT, ichar, lambda storeObj=display, q=ichar: storeObj.set(""))
        for numBut in ("789/", "456*", "123-", "0.+"):
            functionNum = iCalc(self, TOP)
            for char in numBut:
                button(functionNum, LEFT, char, lambda storeObj=display, q=char: storeObj.set(storeObj.get() + q))
        equalButton = iCalc(self, TOP)
        for iEqual in "=":
            if iEqual == "=":
                btniEqual = button(equalButton, LEFT, iEqual)
                btniEqual.bind("<ButtonRelease-1>", lambda e, s=self, storeObj=display: s.calc(storeObj), '+')
            else:
                btniEqual = button(equalButton, LEFT, iEqual, lambda storeObj=display, s='%s' % iEqual: storeObj.set(storeObj.get() + s))

    def calc(self, display):
        try:
            display.set(eval(display.get()))
        except:
            display.set("ERROR")


if __name__ == '__main__':
    app().mainloop()

The calculator in the right frame...

from tkinter import *
import random
import time

root = Tk()
root.geometry("1600x800+0+0")
root.title("Cameron's Chocolate Machine")

text_Input = StringVar()
operator = ""

Tops = Frame(root, width=1600, height=50, bg="powder blue", relief=SUNKEN)
Tops.pack(side=TOP)

f1 = Frame(root, width=1200, height=700, bg="powder blue", relief=SUNKEN)
f1.pack(side=LEFT)


localtime = time.asctime(time.localtime(time.time()))
lblInfo = Label(Tops, font=('simplifica', 50, 'bold'), text="Cameron's Chocolate Machine", fg="Steel Blue", bd=10, anchor='w')
lblInfo.grid(row=0, column=0)

lblInfo = Label(Tops, font=('simplifica', 20), text=localtime, fg="Steel Blue",
                bd=10, anchor='w')
lblInfo.grid(row=1, column=0)


def btnClick(numbers):
    global operator
    operator = operator + str(numbers)
    text_Input.set(operator)


def iCalc(source, side):
    storeObj = Frame(source, borderwidth=4, bd=4, bg="black")
    storeObj.pack(side=side, expand=YES, fill=BOTH)
    return storeObj


def button(source, side, text, command=None):
    storeObj = Button(source, text=text, command=command)
    storeObj.pack(side=side, expand=YES, fill=BOTH)
    return storeObj


class app(Frame):
    def __init__(self):
        Frame.__init__(self)
        self.option_add("*Font", "arial 20 bold")
        self.pack(expand=YES, fill=BOTH)
        self.master.title("Calculator")

        display = StringVar()
        # relief can be FLAT or RIDGE or RAISED or SUNKEN GROOVE
        Entry(self, relief=RIDGE, textvariable=display, justify='right', bd=30, bg='darkgray').pack(side=TOP, expand=YES, fill=BOTH)

        for clearBut in (["CE"], ["C"]):
            erase = iCalc(self, TOP)
            for ichar in clearBut:
                button(erase, LEFT, ichar, lambda storeObj=display, q=ichar: storeObj.set(""))
        for numBut in ("789/", "456*", "123-", "0.+"):
            functionNum = iCalc(self, TOP)
            for char in numBut:
                button(functionNum, LEFT, char, lambda storeObj=display, q=char: storeObj.set(storeObj.get() + q))
        equalButton = iCalc(self, TOP)
        for iEqual in "=":
            if iEqual == "=":
                btniEqual = button(equalButton, LEFT, iEqual)
                btniEqual.bind("<ButtonRelease-1>", lambda e, s=self, storeObj=display: s.calc(storeObj), '+')
            else:
                btniEqual = button(equalButton, LEFT, iEqual, lambda storeObj=display, s='%s' % iEqual: storeObj.set(storeObj.get() + s))

    def calc(self, display):
        try:
            display.set(eval(display.get()))
        except:
            display.set("ERROR")


app().mainloop()
root.mainloop()

Explanation of the code

I put here some explanations of the code, as requested by C S. I will come back later to add more detailed explanations and maybe a video.

from tkinter import *
import time


# initialize the window
root = Tk()
# we put the dimension and position of left corner of the window
root.geometry("1600x800+0+0")
# the title of the window
root.title("Cameron's Chocolate Machine")

# variable to be used later
text_Input = StringVar()
operator = ""

# we have a frame inside the window object root, width 1600 and 50 height
Tops = Frame(root, width=1600, height=50, bg="powder blue", relief=SUNKEN)
# this makes it visible
Tops.pack(side=TOP)

# another frame of 1200 x 700
f1 = Frame(root, width=1200, height=700, bg="powder blue", relief=SUNKEN)
f1.pack(side=LEFT)

# this gets the time
localtime = time.asctime(time.localtime(time.time()))
# here is the big title into a label
lblInfo = Label(Tops, font=('simplifica', 50, 'bold'), text="Cameron's Chocolate Machine", fg="Steel Blue", bd=10, anchor='w')
# this shows the label and put it at row 0, col 0
lblInfo.grid(row=0, column=0)
# This is another label for the time in the row 1, same column as befor
lblInfo = Label(Tops, font=('simplifica', 20), text=localtime, fg="Steel Blue",
                bd=10, anchor='w')
lblInfo.grid(row=1, column=0)

# this puts the digit into the text_Input variable = StringVar() we saw before
def btnClick(numbers):
    global operator
    operator = operator + str(numbers)
    text_Input.set(operator)

# This function creates a frame and makes it visible
def iCalc(source, side):
    storeObj = Frame(source, borderwidth=4, bd=4, bg="black")
    storeObj.pack(side=side, expand=YES, fill=BOTH)
    return storeObj

# This is a constructor for each button of the calculator
# when you call this function it returns a button
def button(source, side, text, command=None):
    storeObj = Button(source, text=text, command=command)
    storeObj.pack(side=side, expand=YES, fill=BOTH)
    return storeObj

# this is the main app for the calculator
class app(Frame):
    def __init__(self):
        # this creates the frame for the calculator
        Frame.__init__(self)
        self.option_add("*Font", "arial 20 bold")
        self.pack(expand=YES, fill=BOTH)
        self.master.title("Calculator")
        # this is a variable to get the value of the following entry object
        display = StringVar()
        # relief can be FLAT or RIDGE or RAISED or SUNKEN GROOVE
        Entry(self, relief=RIDGE, textvariable=display, justify='right', bd=30, bg='darkgray').pack(side=TOP, expand=YES, fill=BOTH)

        for clearBut in (["CE"], ["C"]):
            erase = iCalc(self, TOP)
            for ichar in clearBut:
                button(erase, LEFT, ichar, lambda storeObj=display, q=ichar: storeObj.set(""))
        # here we create all the buttons passing
        for numBut in ("789/", "456*", "123-", "0.+"): # for each of this strings
            functionNum = iCalc(self, TOP) # this is the frame for each string of three symmbols
            for char in numBut: # for every number of symbol in each line ("789" for ex.)
                # a button is created
                button(functionNum, LEFT, char, lambda storeObj=display, q=char: storeObj.set(storeObj.get() + q))
        equalButton = iCalc(self, TOP)
        for iEqual in "=":
            if iEqual == "=":
                btniEqual = button(equalButton, LEFT, iEqual)
                btniEqual.bind("<ButtonRelease-1>", lambda e, s=self, storeObj=display: s.calc(storeObj), '+')
            else:
                btniEqual = button(equalButton, LEFT, iEqual, lambda storeObj=display, s='%s' % iEqual: storeObj.set(storeObj.get() + s))

    def calc(self, display):
        try:
            display.set(eval(display.get()))
        except:
            display.set("ERROR")


app().mainloop()
root.mainloop()

1 Comment

Thanks so much for this. Could you explain to me how this code works, line by line?
0

In your case, I recommend you avoid having .grid() in the same sentence as the command .Buttton().

The steps to make your calculator button are:

  1. First create the Button widget.
  2. Position the Button widget using the .grid() method.

As you are making multiple similar button widgets, you can write a function to make the .Button() widget with the option of defining the button's text display.

You should also add the in_= option in the .grid() method to tell tkinter that the buttons are to be positioned inside frame f2.

Revised Code:

from tkinter import *
import random
import time

root = Tk()
root.geometry("1600x800+0+0")
root.title("Cameron's Chocolate Machine")

text_Input = StringVar()
operator = ""

Tops = Frame(root, width=1600, height=50, bg="powder blue",relief=SUNKEN)
Tops.pack(side=TOP)

f1 = Frame(root, width=800, height=700, bg="powder blue",relief=SUNKEN)
f1.pack(side=LEFT)

f2 = Frame(root, width=300, height=700, bg="powder blue",relief=SUNKEN)
f2.pack(side=RIGHT)

localtime = time.asctime(time.localtime(time.time()))
lblInfo = Label(Tops, font=('simplifica', 50, 'bold'), text="Cameron's Chocolate Machine",
    fg="Steel Blue",bd=10, anchor='w')
lblInfo.grid(row=0,column=0)

lblInfo = Label(Tops, font=('simplifica', 20), text=localtime,fg="Steel Blue",
    bd=10,anchor='w')
lblInfo.grid(row=1,column=0)

def btnClick(numbers):
    global operator
    operator= operator + str(numbers)
    text_Input.set(operator)

txtDisplay = Entry(f2, font=('arial',20,'bold'),textvariable=text_Input, bd=30, 
    insertwidth=4,bg='powder blue', justify='right')
txtDisplay.grid(columnspan=4)

#CODE THAT IS NOT PRINTING THE BUTTON IS BELOW - AMENDED
def btnCreate(number):
    """Function to make calculator button."""
    return Button(f2, padx=16, pady=16, bd=8, fg="black", bg="powder blue", 
                  font=('arial', 20,'bold'), text=str(number),
                  command=lambda:btnClick(number))

btn7= btnCreate(7)
btn8= btnCreate(8)
btn9= btnCreate(9)
badd= btnCreate('+')

btn7.grid(in_=f2, row=2,column=0)
btn8.grid(in_=f2, row=2,column=1)
btn9.grid(in_=f2, row=2,column=2)
badd.grid(in_=f2, row=2,column=3)

#Below syntax is more cluttered  
"""Button(f2,padx=16,pady=16,bd=8,fg="black",font=('arial', 20, 
    'bold'),text="7",bg="powder blue",command=lambda:btnClick(7))
btn7.grid(row=2,column=0)

btn8=Button(f2,padx=16,pady=16,bd=8,fg="black",font=('arial', 20, 'bold'),
    text="8",bg="powder blue",command=lambda: btnClick(8))
btn8.grid(row=2,column=1)

btn9=Button(f2,padx=16,pady=16,bd=8,fg="black",font=('arial', 20, 'bold'),
    text="9",bg="powder blue",command=lambda: btnClick(9))
btn9.grid(row=2,column=2)

Addition=Button(f2,padx=16,pady=16,bd=8,fg="black",font=('arial', 20, 'bold'),
    text="9",bg="powder blue",command=lambda: btnClick("+"))
Additional.grid(row=2,column=3)"""

root.mainloop()

Comments

0

You have the same mistake in the following lines:

btn7=Button(...,command=lambda:btnClick(7).grid(...))

btn8=Button(...,command=lambda: btnClick(8).grid(...))

btn9=Button(...,command=lambda: btnClick(9).grid(...))

Addition=Button(...,command=lambda: btnClick("+").grid(...))

The mistake is that the layout manager method calls(grid(...)) are included in the command reference as opposed to being called on the widgets. Simply fix the error moving the last closing parenthesis, just before grid calls:

btn7=Button(...,command=lambda:btnClick(7)).grid(...)

btn8=Button(...,command=lambda: btnClick(8)).grid(...)

btn9=Button(...,command=lambda: btnClick(9)).grid(...)

Addition=Button(...,command=lambda: btnClick("+")).grid(...)

This is stil terrible as btn7, btn8,btn9, and Addition are all Nones. Better separate the layout methods as well:

btn7=Button(...)
btn8=Button(...)
btn9=Button(...)
Addition=Button(...)
...
btn7.grid(...)
btn8.grid(...)
btn9.grid(...)
Addition.grid(...)

Comments

0

You can make better ui better colour in less lines of code. Have a look at my Calculator_PRO.

Here is the part that generates and places the buttons at respective co-ordinates

click here to see the demo

Sample Code:

from tkinter import *

# Caculator GUI
window = Tk()
window.title("Calculator PRO v"+str(version))
window.geometry("270x430")
window.configure(background='#1F2937')


Input = Label(window,bg = '#1F2937', text = "0", anchor="e", justify=RIGHT, width=11, font=('', 36))
Input.place(x=0, y=30)

btns = []
btn_names = ['DEL', 'C', 'x²', '√','1', '2', '3', '+', '4', '5', '6', '-', '7', '8', '9', 'x', '.', '0', '=', '÷']

# Generate Buttons
for btn in btn_names:
    if btn in "1234567890.": color = "#10B981"
    if btn in ('+', '-', 'x', '÷', '√', 'x²'): color = "#F59E0B"
    if btn in "=": color = "#047857"
    if btn in ("C", "DEL"): color = "#2563EB"
    btns.append(Button(window, text=btn, width=55, height=55, font=('', 18), bg = color, command=lambda btn=btn: getInput(btn)))

# Place those buttons
row = 0
col = 0
top_pad = 100
left_pad = 10
for btn in btns:
    if col >= 4:
        col = 0
        row += 1
    if row >= 5: break
    btn.place(x = (col*65+left_pad), y = (row*65+top_pad))
    col += 1


window.mainloop()

1 Comment

It was all good, until I saw the eval()(Calcuator PRO).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.