Creating a GUI Calculator, I think I mangled the grid, help?

So I’m trying to streamline the grid for the UI, and I messed up the order, and for the life of me can’t get the button’s organized.

import tkinter as tk
import math

class Calculator:
    def __init__(self, root):
        self.root = root
        self.root.title("Scientific Calculator")
        self.root.configure(background='white')
        self.root.geometry("480x568+450+90")

        self.current = ''
        self.total = 0
        self.input_value = True
        self.check_sum = False
        self.op = ''
        self.result = False

        self.create_ui()

    def create_ui(self):
        self.entry = tk.Entry(self.root, font=('Helvetica', 20, 'bold'), bg='black', fg='white', bd=30, width=28, justify=tk.RIGHT)
        self.entry.grid(row=0, column=0, columnspan=4, pady=1)
        self.entry.insert(0, "0")

        button_grid = [
            "7894",
            "456",
            "0.+-"
        ]

        row, col = 2, 4
        for row_data in button_grid:
            for char in row_data:
                btn = self.create_button(char, row, col)
                col += 1
            row += 1
            col = 0

        special_buttons = [
            ("C", 1, 0, self.clear_entry),
            ("CE", 1, 1, self.all_clear_entry),
            ("√", 1, 5, self.square_root),
            ("+", 1, 6, lambda: self.operation("add")),
            ("-", 2, 5, lambda: self.operation("sub")),
            ("*", 3, 6, lambda: self.operation("multi")),
            ("/", 6, 5, lambda: self.operation("divide")),
            ("=", 6, 6, self.sum_of_total),
        ]

        for label, r, c, command in special_buttons:
            self.create_button(label, r, c, command)
            

        scientific_functions = [
            ("pi", self.pi),
            ("e", self.e),
            ("+/-", self.math_pm),
            ("sin", self.sin),
            ("cos", self.cos),
            ("tan", self.tan),
            ("sinh", self.sinh),
            ("cosh", self.cosh),
            ("tanh", self.tanh),
            ("log", self.log),
            ("exp", self.exp),
        ]

        row, col = 1, 4
        for label, func in scientific_functions:
            self.create_button(label, row, col, func)
            if col == 7:
                col = 4
                row += 1
            else:
                col += 1

    def create_button(self, text, row, column, command=None):
        btn = tk.Button(self.root, text=text, width=6, height=2, bg='powder blue', font=('Helvetica', 20, 'bold'), bd=4,
                        command=command if command else lambda t=text: self.number_enter(t))
        btn.grid(row=row, column=column, pady=1)
        return btn

    def number_enter(self, num):
        if self.result:
            self.current = ''
            self.result = False

        if self.input_value:
            self.current = num
            self.input_value = False
        else:
            self.current += str(num)

        self.display(self.current)

    def operation(self, op):
        self.current = float(self.current)
        if self.check_sum:
            self.valid_function()
        elif not self.result:
            self.total = self.current
            self.input_value = True
        self.check_sum = True
        self.op = op
        self.result = False

    def valid_function(self):
        if self.op == "add":
            self.total += self.current
        if self.op == "sub":
            self.total -= self.current
        if self.op == "multi":
            self.total *= self.current
        if self.op == "divide":
            self.total /= self.current
        self.input_value = True
        self.check_sum = False
        self.display(self.total)

    def sum_of_total(self):
        self.result = True
        self.current = float(self.current)
        if self.check_sum:
            self.valid_function()
        else:
            self.total = float(self.entry.get())
        self.display(self.total)

    def display(self, value):
        self.entry.delete(0, tk.END)
        self.entry.insert(0, value)

    def clear_entry(self):
        self.result = False
        self.current = "0"
        self.display(0)
        self.input_value = True

    def all_clear_entry(self):
        self.clear_entry()
        self.total = 0

    def pi(self):
        self.result = False
        self.current = math.pi
        self.display(self.current)

    def e(self):
        self.result = False
        self.current = math.e
        self.display(self.current)

    def math_pm(self):
        self.result = False
        self.current = -float(self.entry.get())
        self.display(self.current)

    def square_root(self):
        self.result = False
        self.current = math.sqrt(float(self.entry.get()))
        self.display(self.current)

    def sin(self):
        self.result = False
        self.current = math.sin(math.radians(float(self.entry.get())))
        self.display(self.current)

    def cos(self):
        self.result = False
        self.current = math.cos(math.radians(float(self.entry.get())))
        self.display(self.current)

    def tan(self):
        self.result = False
        self.current = math.tan(math.radians(float(self.entry.get())))
        self.display(self.current)

    def sinh(self):
        self.result = False
        self.current = math.sinh(math.radians(float(self.entry.get())))
        self.display(self.current)

    def cosh(self):
        self.result = False
        self.current = math.cosh(math.radians(float(self.entry.get())))
        self.display(self.current)

    def tanh(self):
        self.result = False
        self.current = math.tanh(math.radians(float(self.entry.get())))
        self.display(self.current)

    def log(self):
        self.result = False
        self.current = math.log(float(self.entry.get()))
        self.display(self.current)

    def exp(self):
        self.result = False
        self.current = math.exp(float(self.entry.get()))
        self.display(self.current)

def main():
    root = tk.Tk()
    calculator = Calculator(root)
    root.mainloop()

if __name__ == "__main__":
    main()

I have not run the code just read it.

4 appears twice ,1,2 and 3 are missing it seems.

col starts as 4 but is reset to 0, is that right?

Hi Joseph,

Why not start with a simple grid like this?
https://www.reddit.com/r/Python/comments/ofr75b/i_made_a_calculator_with_17_lines_of_code/?rdt=37844

2 Likes

Hey Joseph so I tried to get the buttons layed out quite correctly but the code is messy with diffrent data types to perform calculations… nyw hope its not too late or you got a way around it to streamline the grid if not check this calculator
Just know how to place items on the grid and for you to know this just use co-ordinates. Like 0,0 is row 1 column 0. So this means the button will be at the top left corner. 1,0 is the second row on the first column.
Keep in mind positoning is index based… nywy I have commented some cdoe for you to play with… cheers

1 Like

Here is my updated code thus far:
I plan to keep adding functions to this and to make it better as time goes on.
Thanks for the tips thus far!

import tkinter as tk
import math

class Calculator:
    def __init__(self, root):
        self.root = root
        self.root.title('Scientific Calculator')
        self.disp = tk.Label(root, text='')
        self.disp.grid(column=0, row=0, columnspan=5)
        self.keys = [
            '(', ')', 'C', '<', '7', '8', '9', '/', '4', '5', '6', '*', '1', '2', '3', '-', '.', '0', '=', '+', 'M+', 'MR',
            'MC','sin','cos', 'tan', 'tanh', 'cosh', '√', 'pi', 'log', 'exp','phi','e', '^'
        ]

        self.create_buttons()
        self.entering_power = False
        self.base = ''
        self.memory = None

    def create_buttons(self):
        self.button_grid = []
        for n, key in enumerate(self.keys):
            row, col = n // 4 + 1, n % 4 + 1
            button = tk.Button(self.root, text=key, command=lambda k=key: self.bt_press(k))
            button.grid(column=col, row=row)
            self.button_grid.append(button)

    def bt_press(self, key):
        if key == 'C':
            self.disp['text'] = ''
            self.entering_power = False
        elif key == '<':
            if '^' in self.disp['text']:
                self.entering_power = False
            self.disp['text'] = self.disp['text'][:-1]
        elif key == '=':
            if self.entering_power:
                self.power_function()
                self.entering_power = False
            else:
                self.disp['text'] = str(round(eval(self.disp['text']), 6))
        elif key == 'M+':
            self.memory_store()
        elif key == 'MR':
            self.memory_recall()
        elif key == 'MC':  
            self.memory_clear()
        elif key == 'cos':
            self.cos_function
        elif key == 'sin':
            self.sin_function()
        elif key == 'tan':
            self.tan_function()
        elif key == 'tanh':
            self.tanh_function()
        elif key == 'cosh':
            self.cosh_function()
        elif key == '√':
            self.square_root_function()
        elif key == 'pi':
            self.pi_function()
        elif key == 'log':
            self.log_function()
        elif key == 'exp':
            self.exp_function()
        elif key == 'phi':
            self.phi_function()
        elif key == 'e':
            self.eul_function()
        elif key == '^':
            if '^' not in self.disp['text']:
                self.disp['text'] += '^'
                self.entering_power = True
        else:
            self.disp['text'] += key

    def power_function(self):
        try:
            expression = self.disp['text']
            base, exponent = expression.split('^')
            base = float(base)
            exponent = float(exponent)
            result = base ** exponent
            self.disp['text'] = str(round(result, 6))
            self.entering_power = False
        except (ValueError, ZeroDivisionError, OverflowError):
            self.disp['text'] = 'Error'

    def memory_store(self):
        self.memory = self.disp['text']

    def memory_clear(self):
        self.memory = None

    def memory_recall(self):
        if hasattr(self, 'memory'):
            self.disp['text'] += self.memory

    def sin_function(self):
        try:
            result = math.sin(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def phi_function(self):
        try:
            result = math.phi(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def tan_function(self):
        try:
            result = math.tan(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def cos_function(self):
        try:
            result = math.cos(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def tanh_function(self):
        try:
            result = math.tanh(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def cosh_function(self):
        try:
            result = math.cosh(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def square_root_function(self):
        try:
            result = math.sqrt(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def pi_function(self):
        self.disp['text'] = str(math.pi)

    def log_function(self):
        try:
            result = math.log(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def exp_function(self):
        try:
            result = math.exp(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def eul_function(self):
        try:
            self.disp['text'] = str(math.e)
        except ValueError:
            self.disp['text'] = 'Error'

def main():
    root = tk.Tk()
    calculator = Calculator(root)
    root.mainloop()

if __name__ == "__main__":
    main()

if anyone can help, I’m still having trouble getting the parenthesis to work correctly, I’ve parsed the statement but can’t get it to not spit out an error.

import tkinter as tk
import math
import ast

class Calculator:
    def __init__(self, root):
        self.root = root
        self.root.title('Scientific Calculator')
        self.disp = tk.Label(root, text='')
        self.disp.grid(column=0, row=0, columnspan=5)
        self.keys = [
            '(', ')', 'C', '<', '7', '8', '9', '/', '4', '5', '6', '*', '1', '2', '3', '-', '.', '0', '=', '+', 'M+', 'MR',
            'MC', 'sin', 'cos', 'tan', 'tanh', 'asin', 'acos', 'atan', 'cosh', 'acosh', '√', 'pi', 'log', 'exp','phi','e', '^'
        ]

        self.create_buttons()
        self.entering_power = False
        self.base = ''
        self.memory = None

    def create_buttons(self):
        self.button_grid = []
        for n, key in enumerate(self.keys):
            row, col = n // 4 + 1, n % 4 + 1
            button = tk.Button(self.root, text=key, command=lambda k=key: self.bt_press(k))
            button.grid(column=col, row=row)
            self.button_grid.append(button)

    def bt_press(self, key):
        if key == 'C':
            self.disp['text'] = ''
            self.entering_power = False
        elif key == '<':
            if '^' in self.disp['text']:
                self.entering_power = False
            self.disp['text'] = self.disp['text'][:-1]
        elif key == '=':
            if self.entering_power:
                self.power_function()
                self.entering_power = False
            elif self.disp['text']:
                try:
                    expression = self.disp['text'].replace('(', '*(')
                    result = ast.literal_eval(expression)
                    self.disp['text'] = str(round(result, 6))
                except (ValueError, ZeroDivisionError, OverflowError, SyntaxError):
                    self.disp['text'] = 'Error'
            else:
                self.disp['text'] = str(round(eval(self.disp['text']), 6))
        elif key == 'M+':
            self.memory_store()
        elif key == 'MR':
            self.memory_recall()
        elif key == 'MC':  
            self.memory_clear()
        elif key == 'cos':
            self.cos_function
        elif key == 'sin':
            self.sin_function()
        elif key == 'tan':
            self.tan_function()
        elif key == 'tanh':
            self.tanh_function()
        elif key == 'cosh':
            self.cosh_function()
        elif key == '√':
            self.square_root_function()
        elif key == 'pi':
            self.pi_function()
        elif key == 'log':
            self.log_function()
        elif key == 'exp':
            self.exp_function()
        elif key == 'phi':
            self.phi_function()
        elif key == 'e':
            self.eul_function()
        elif key =='asin':
            self.asin_function()
        elif key == "acos":
            self.acos_function
        elif key == 'atan':
            self.atan_function
        elif key == 'acosh':
            self.acosh_function
        elif key == '^':
            if '^' not in self.disp['text']:
                self.disp['text'] += '^'
                self.entering_power = True
        else:
            self.disp['text'] += key

    def power_function(self):
        try:
            expression = self.disp['text']
            base, exponent = expression.split('^')
            base = float(base)
            exponent = float(exponent)
            result = base ** exponent
            self.disp['text'] = str(round(result, 6))
            self.entering_power = False
        except (ValueError, ZeroDivisionError, OverflowError):
            self.disp['text'] = 'Error'

    def memory_store(self):
        self.memory = self.disp['text']

    def memory_clear(self):
        self.memory = None

    def memory_recall(self):
        if hasattr(self, 'memory'):
            self.disp['text'] += self.memory

    def sin_function(self):
        try:
            result = math.sin(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def asin_function(self):
        try:
            result = math.asin(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'
    
    def atan_function(self):
        try:
            result = math.atan(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'
    
    def sin_function(self):
        try:
            result = math.sin(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def acosh_function(self):
        try:
            result = math.acosh(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'        

    def acos_function(self):
        try:
            result = math.acos(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def phi_function(self):
        try:
            result = math.phi(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def tan_function(self):
        try:
            result = math.tan(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def cos_function(self):
        try:
            result = math.cos(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def tanh_function(self):
        try:
            result = math.tanh(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def cosh_function(self):
        try:
            result = math.cosh(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def square_root_function(self):
        try:
            result = math.sqrt(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def pi_function(self):
        self.disp['text'] = str(math.pi)

    def log_function(self):
        try:
            result = math.log(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def exp_function(self):
        try:
            result = math.exp(float(self.disp['text']))
            self.disp['text'] = str(round(result, 6))
        except ValueError:
            self.disp['text'] = 'Error'

    def eul_function(self):
        try:
            self.disp['text'] = str(math.e)
        except ValueError:
            self.disp['text'] = 'Error'


def main():
    root = tk.Tk()
    calculator = Calculator(root)
    root.mainloop()

if __name__ == "__main__":
    main()

Please share the error you are seeing so we know what you are seeing.